混淆 Java 时间解析 UTC

Confusion with Java Time parsing UTC

我对 java 中的时间处理感到困惑。长期以来,我一直在假设如果将时间戳指定为祖鲁时间,java 将处理与当地时间相关的偏移量。

举例说明。我目前在 BST,其偏移量为 UTC +1。考虑到这一点,我希望这个祖鲁时间:

2016-09-12T13:15:17.309Z

成为

2016-09-12T14:15:17.309 

解析后的LocalDateTime。这是因为我的默认系统时间设置为BST,而上面的时间戳(祖鲁时间)指定它是UTC时间。

但是请考虑以下示例:

        String ts = "2016-09-12T13:15:17.309Z";
        LocalDateTime parse = LocalDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println(parse);

这将打印:

2016-09-12T13:15:17.309

因此,解析为 LocalDateTime 的时间戳不会被识别为 UTC 时间,而是直接被视为本地时间。 所以我想,也许我需要将它解析为 ZonedDateTime 并将其专门转换为 LocalDateTime 以获得正确的本地时间。通过此测试:

        String ts = "2016-09-12T13:15:17.309Z";
        ZonedDateTime parse = ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println(parse);
        System.out.println(parse.toLocalDateTime());

我得到输出:

2016-09-12T13:15:17.309Z
2016-09-12T13:15:17.309

两个日期的输出相同。

我能找到的正确解析它的唯一方法是:

    String ts = "2016-09-12T13:15:17.309Z";
    Instant instant = Instant.parse(ts); // parses UTC
    LocalDateTime ofInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    System.out.println(instant);
    System.out.println(ofInstant);

这会打印:

2016-09-12T13:15:17.309Z
2016-09-12T14:15:17.309

哪个是正确的。

所以问题是:

问题在于 jersey/jackson 的 java 时间模块使用 ISO 格式和常规 LocalDateTime#parse 方法解析时间戳。我意识到我的时间并没有停止,因为他们被视为 LocalTime 而实际上他们是在祖鲁时间。

您误解了 LocalDateTime 的目的。

引用 class 文档:

A date-time without a time-zone in the ISO-8601 calendar system, such as {@code 2007-12-03T10:15:30}.

This class does not store or represent a time-zone. Instead, it is a description of the date, as used for birthdays, combined with the local time as seen on a wall clock. It cannot represent an instant on the time-line without additional information such as an offset or time-zone.

所以它的明确目的只是表示日期和时间而没有时区。它的目的是 而不是 来表示日期和时间 在本地时区

因此每次转换都只是去除时区。

因此,出于您的目的,您需要 ZonedDateTimeZoneId.systemDefault(),正如您在第三个示例中已经使用的那样。

对于你的第二个例子,这可能是:

String ts = "2016-09-12T13:15:17.309Z";
ZonedDateTime parse = 
    ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME)
        .withZoneSameInstant(ZoneId.systemDefault());
System.out.println(parse);
System.out.println(parse.toLocalDateTime());

tl;博士

示例:

Instant.parse( "2016-09-12T13:15:17.309Z" )
       .atZone( ZoneId.of( "Europe/London" ) )
       .toString();

2016-09-12T14:15:17.309+01:00[Europe/London]

Run in IdeOne.com.

详情

是正确的。你误解了LocalDateTimeclass的意思。它 而不是 表示特定地点的日期时间。恰恰相反,它 而不是 代表一个真实的时刻。

我建议将 Instant 视为 java.time 中的基本构建块 class。 Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds(最多九 (9) 位小数)。

您的输入字符串符合 Instant class 默认使用的 ISO 8601 格式,用于解析和生成字符串表示。最后的 ZZulu 的缩写,表示 UTC。无需指定格式模式。

Instant instant = Instant.parse( "2016-09-12T13:15:17.309Z" );

作为程序员,您应该学会主要在 UTC 中思考和工作。忘记你自己的时区。将 UTC 视为唯一真实时间。应用时区作为变体,并且仅在需要时应用。

指定一个proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as BST or EST or IST as they are not true time zones, not standardized, and not even unique(!). If by BST you meant British Summer Time, then the actual time zone name would be Europe/London。 java.time classes 将确定如何调整任何异常情况,包括夏令时 (DST)。

ZoneId z = ZoneId.of( "Europe/London" );
ZonedDateTime zdt = instant.atZone( z );

关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode,建议迁移到java.time。

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

在哪里获取java.time classes?

  • Java SE 8 and SE 9 及更高版本
    • 内置。
    • 标准 Java API 的一部分,带有捆绑实施。
    • Java 9 添加了一些小功能和修复。
  • Java SE 6 and SE 7
  • Android
    • ThreeTenABP项目专门为Android改编了ThreeTen-Backport(上面提到的)。
    • 参见

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.