Java 8 - 尝试使用文本时区 ID 解析时间戳

Java 8 - Trying to parse timestamp with textual TimeZone ID

呃...我这辈子都想不通。我正在使用 Java 8 并尝试做一些像解析时间戳一样简单的事情,其中​​时区 ID 是文本值,例如 HST:

作品

ZonedDateTime timestamp = ZonedDateTime.parse("2018-10-29T12:00:12.456-10:00");

不起作用

ZonedDateTime timestamp = ZonedDateTime.parse("2018-10-29T12:00:12.456HST");

并得到这个错误:

java.time.format.DateTimeParseException: Text '2018-10-29T12:00:12.456HST' could not be parsed at index 23

有谁知道如何解析时区 ID 作为文本值出现的时间戳?

有两个问题:

1) ZonedDateTime.parse 方法仅解析符合 ISO_ZONED_DATE_TIME 格式的字符串,您可以在此处找到它的外观描述: https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_ZONED_DATE_TIME

为了解析您的格式,您必须创建自己的 dateTimeFormatter。

这个格式化程序看起来像这样

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral('T')
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .appendZoneId()
            .toFormatter();

如果您使用标准时区(如 GMT、UTC 等),此格式化程序将起作用。 问题是 HST 不是区域的标准格式并且不受支持。您可以通过以下方式查看支持的时区:

System.out.println(ZoneId.getAvailableZoneIds());

如果您仍想使用 HST 区域,则必须像这样为您的自定义区域添加 ZoneRulesProvider:

  ZoneRulesProvider.registerProvider(new ZoneRulesProvider() {
        @Override
        protected Set<String> provideZoneIds() {
            return Collections.singleton("HST");
        }

        @Override
        protected ZoneRules provideRules(String zoneId, boolean forCaching) {
            return ZoneRules.of(ZoneOffset.ofHours(10));
        }

        @Override
        protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
            TreeMap map =  new TreeMap<>();
            map.put("HST",ZoneRules.of(ZoneOffset.ofHours(10)));
            return  map;
        }
    });

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral('T')
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .appendZoneId()                
            .toFormatter();

    ZonedDateTime timestamp = ZonedDateTime.parse("2018-10-29T12:00:12.456HST", formatter);
    System.out.println(timestamp);

这应该有效。