【问题标题】:Java SimpleDateFormat.getTimeZone().getID() returns Asia/Jerusalem instead of Asia/KolkataJava SimpleDateFormat.getTimeZone().getID() 返回 Asia/Jerusalem 而不是 Asia/Kolkata
【发布时间】:2017-12-01 11:14:39
【问题描述】:

SimpleDateFormat's getTimeZone().getID() 方法返回 Asia/Jerusalem 而不是 Asia/Kolkata 的日期格式为EEE MMM dd HH:mm:ss z yyyy。实际上,在我的开发机器中,它按预期返回了亚洲/加尔各答。但在其他一些机器(生产环境)中,它返回 Asia/Jerusalem 而不是 Asia/Kolkata。知道是什么原因造成的以及如何解决它。源码如下:

String input = "Mon Jun 12 13:29:47 IST 2017";
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");          
sdf.parse(input);
TimeZone timeZone = sdf.getTimeZone();
System.out.println(timeZone.getID());

【问题讨论】:

  • 时区缩写,例如 IST、EST 等...不是唯一的。 IST 代表以色列标准时间和印度标准时间。您应该使用不同的方法来表示时间戳中的时区。
  • 三个和四个字母的时区缩写是一个众所周知的问题。 IST 的第三种解释是爱尔兰标准时间(欧洲/都柏林)。
  • 在哪里可以找到给定时区缩写的时区 ID 列表。例如,对于缩写 IST,时区 ID 为 Asia/Jerusalem、Asia/Kolkata、Europe/Dublin。
  • 最好将最后一条评论发布为a separate question。让我们继续。

标签: java timezone simpledateformat date-format zoneddatetime


【解决方案1】:

知道是什么原因造成的……

三个和四个字母的时区缩写是一个众所周知的问题。 IST 的第三种解释是爱尔兰标准时间(欧洲/都柏林)。我不知道究竟是什么原因导致一个 JVM 更喜欢一种解释而不是另一种。在至少一种情况下,我看到它比其他解释更喜欢它的默认时区设置。因此,如果您的开发机器具有亚洲/加尔各答时区设置而您的生产机器没有,这可能就是解释。但是,我不会将此作为确定的事实,而且我希望编写足够健壮的代码以在具有不同时区设置的计算机和 JVM 上运行。

...以及如何解决它。

理想的解决方案:避免获取包含三个或四个字母时区缩写的日期时间字符串。首选与 UTC 的区域偏移和/或大陆/城市形式的时区名称。我承认这并不总是可能的。

鉴于您的输入字符串,因为 SimpleDateFormatTimeZone 已过时,并且现代 Java 日期和时间 API 对程序员更加友好,并且您还使用 ZonedDateTime 类标记了您的问题,这是现代 API,让我们先采用现代解决方案:

    DateTimeFormatter dtf = new DateTimeFormatterBuilder()
            .appendPattern("EEE MMM dd HH:mm:ss ")
            .appendZoneText(TextStyle.SHORT, Collections.singleton(ZoneId.of("Asia/Kolkata")))
            .appendPattern(" uuuu")
            .toFormatter(Locale.ROOT);
    ZonedDateTime dateTime = ZonedDateTime.parse(input, dtf);
    System.out.println(dateTime.getZone());

打印出来:

Asia/Kolkata

我传递给appendZoneText() 的第二个参数是一组首选时区。在the documentation 中,它说“如果要解析的纹理区域名称不是唯一的,则将使用匹配的首选区域 ID。”这就是我们在这里所追求的。

在我的计算机上,我还能够使用过时的类在您的代码中解决问题。我在解析之前插入了以下行。

    sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));

但是,旧类的文档比较模糊,所以我不太确定这个解决方案是否总是有效。

顺便说一句,无论您使用旧类还是现代类,我建议您始终为解析提供明确的语言环境。 “Mon” 和 “Jun” 是英文的,因此除非您指定语言环境,否则解析将无法在具有非英语语言环境设置的计算机上进行。让我猜猜,你的日期字符串不是英文的,因为它来自说英语的语言环境,而只是因为英语是计算中的通用语言。如果是这样,我认为Locale.ROOT 合适。我已经在我的代码中使用它。要在你的中使用它,请将它作为参数添加到构造函数中:

    SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ROOT);

Locale.ENGLISH 适用于其他英语语言环境。

【讨论】:

  • 我一直认为 IST 是爱尔兰标准时间,但在夏季使用 DateTimeFormatterz zzzz 模式会给出“IST Irish Summer Time”和"GMT Greenwich Mean Time" in the winter .但我也发现"Irish Standard Time" 的名字也是used for the summer time。那么,这两个名字都有效吗?我们真的需要一个标准(ISO/RFC/whatever)……
  • @Hugo 忍不住笑了,希望大家见谅。在许多答案和 cmets 中,我引用了 List of time zone abbreviations 的“爱尔兰标准时间”,尽管考虑到用法,“夏令时”显然更有意义。爱尔兰确实使用夏令时 (DST) 和冬季的标准时间,所以这只会使歧义变得更糟,并强调您和我都在提出的观点:三个字母缩写是模棱两可和非标准的,应该避免.
  • 我想知道他们为什么将 DST 称为“标准”。无论如何,由于使用了这两个名称,也许没有一个是错误的(尽管这很令人困惑)。别担心,当我发现这个时我也笑了。在有人对其进行标准化之前,这就是我们所能做的……
  • 我认为标准化为时已晚,@Hugo。在这一点上,没有人会放弃自己长期以来的解释。 “避免”是要走的路……
猜你喜欢
  • 2013-05-11
  • 1970-01-01
  • 2021-04-26
  • 2023-03-04
  • 2014-06-07
  • 2021-04-27
  • 1970-01-01
  • 2016-08-04
  • 2013-05-30
相关资源
最近更新 更多