IST映射到java.time库中的错误ZoneId

时间:2019-08-30 22:35:51

标签: java java.time

我正在尝试从格式为(yyyy-MM-dd HH:mm z)的字符串解析ZonedDateTime。输入字符串(2019-08-29 00:00 IST)生成UTC时间戳。

调试使我想到了将IST的ZoneId映射到的位置 大西洋/雷克雅未克没有意义。应该将其映射到亚洲。

timestamp = ZonedDateTime.parse(timeInput, DATE_WITH_TIMEZONE_FORMATTER)
            .toInstant().toEpochMilli()

其中

DateTimeFormatter DATE_WITH_TIMEZONE_FORMATTER = DateTimeFormatter
      .ofPattern(DATE_TIME_WITH_TIMEZONE_PATTERN).withChronology(IsoChronology.INSTANCE);

我在这里想念东西吗?

2 个答案:

答案 0 :(得分:2)

我不知道您为什么要进入冰岛,即使在主TZDB IST中也仅参考爱尔兰标准时间(以及1968年以前错误的爱尔兰夏令时),以色列标准时间和印度标准时间出现。冰岛的出现可能是Java时区数据库中的错误。

经过进一步调查,我发现仅当当前语言环境的 语言 设置为某些非空值时,才会出现该问题。如果创建没有指定语言的语言环境,则会得到Asia/Kolkata,但是如果存在该语言(任何语言),它将返回Atlantic/Reykjavik。这很可能是Java实现中的错误。

    String input = "2019-08-29 00:00 IST";
    Locale loc = new Locale.Builder().setRegion("US").build(); // Note no language
    System.out.println(loc.toString());
    DateTimeFormatter DATE_WITH_TIMEZONE_FORMATTER = 
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm z").withLocale(loc);
    ZonedDateTime zdt = ZonedDateTime.parse(input, DATE_WITH_TIMEZONE_FORMATTER);
    System.out.println(zdt);

这产生

_US
2019-08-29T00:00+05:30[Asia/Kolkata]

但要改变

    Locale loc = new Locale.Builder().setLanguage("ta").build();

产生

ta
2019-08-29T00:00Z[Atlantic/Reykjavik]

无论如何,裸露的时区IST在上下文之外都是模棱两可的。为避免混淆,如果希望IST始终为Asia/Kolkata,则可能必须在解析之前修改传入的数据。

答案 1 :(得分:2)

首先,如果有什么可以避免的方法,请不要依赖三个字母的时区缩写。它们是模棱两可的,可能更多。当您说IST应该映射到亚洲时,仍然保留在Asia / Tel_Aviv和Asia / Kolkata之间进行选择(以及这两个别名,即Asia / Jerusalem和Asia / Calcutta)。在世界其他地方,IST可能意味着爱尔兰的夏令时,也可能意味着冰岛的标准时间(或类似的时间;它当然是有道理的)。这不是我第一次看到IST被认可为Atlantic / Reykjavik。

如果您无法避免解析IST,请通过appendZoneText的两个参数DateTimeFormatterBuilder来控制解释。它接受一组首选区域:

DateTimeFormatter DATE_WITH_TIMEZONE_FORMATTER = new DateTimeFormatterBuilder()
        .appendPattern("yyyy-MM-dd HH:mm ")
        .appendZoneText(TextStyle.SHORT, Collections.singleton(ZoneId.of("Asia/Kolkata")))
        .toFormatter(Locale.ENGLISH);

用我放置Asia/Kolkata的首选首选区域替换。其余的应该不会造成麻烦:

    String timeInput = "2019-08-29 00:00 IST";
    ZonedDateTime zdt = ZonedDateTime.parse(timeInput, DATE_WITH_TIMEZONE_FORMATTER);
    System.out.println("Parsed ZonedDateTime: "+ zdt);
    long timestamp = zdt
            .toInstant().toEpochMilli();
    System.out.println("timestamp: " + timestamp);

输出:

Parsed ZonedDateTime: 2019-08-29T00:00+05:30[Asia/Kolkata]
timestamp: 1567017000000

链接: Time Zone Abbreviations – Worldwide List(您会注意到IST在列表中排名第三,而其他缩写也含糊不清)。