【问题标题】:Understanding specific UTC time format YYYY-MM-DDTHH:MM:SS.SSSZ了解特定的 UTC 时间格式 YYYY-MM-DDTHH:MM:SS.SSSZ
【发布时间】:2016-10-02 01:30:42
【问题描述】:

我有两个相关的问题。

假设在 BST 中运行的程序以 UTC YYYY-MM-DDTHH:MM:SS.SSSZ 格式生成当前时间的日期时间值

还假设伦敦的当前时间是 2016-06-01 12:33:54

  1. 如果程序给出的当前时间是 2016-06-01T11:33:54.000Z ,是不是程序出错了?

  2. BST 的夏季偏移如何以 YYYY-MM-DDTHH:MM:SS.SSSZ 的相应时间格式记录

我假设 YYYY-MM-DDTHH:MM:SS+0001 我正确吗?

【问题讨论】:

  • 1) 不,因为有夏季偏移。 UTC 不会随着夏季偏移而改变。 2) YYYY-MM-DDTHH:MM:SS+01:00
  • 那么上面的例子程序给出的时间应该是2016-06-01T11:33:54.000+01:00 你的意思是?
  • 不应该是2016-06-01T11:33:54.000Z2016-06-01T12:33:54.000+01:002016-06-01T13:33:54.000+02:002016-06-01T15:03:54.000+03:30 或或或任何东西
  • 谢谢!!这有帮助。

标签: java utc iso8601 gmt


【解决方案1】:

首先请阅读iso8601信息。处理不同时区(例如服务器时区和客户端时区)的时间变得越来越普遍,该标准非常有用。

请特别阅读有关 UTC 或“祖鲁”时间的信息here

  1. 程序是正确的,因为伦敦时间比夏季的“UTC”时间早一小时

  2. 结尾的“Z”是 UTC (Zulu) 的缩写。你也可以写“+00:00”而不是“Z”。 SS.SSS 指的是秒和毫秒 - 与时区无关。在 devnull 的评论中,他向您展示了如何为夏季应用偏移量。

编辑

关于iso8601时区是否包含时区以及时区是否真的会被打印出来的问题,在cmet中有一些讨论。

这完全取决于日期/时间的实现。如果我们使用SimpleDateFormat,则支持时区并将被打印。

这里有一个代码示例来说明

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(formatter.format(new Date()));
formatter.setTimeZone(TimeZone.getTimeZone("Europe/London"));
System.out.println(formatter.format(new Date()));

输出

2016-06-02T12:53:14.924Z
2016-06-02T13:53:14.925+01:00

当然,如果您使用不同的日期/时间库,例如joda-time,那么实现细节会有所不同。

编辑:正如@DerrylThomas 指出的SimpleDateFormat 明智地使用小写y 多年 - 除非它打算使用周年 - 稍微解释一下详细信息在另一个类似问题的答案https://stackoverflow.com/a/56911450

【讨论】:

  • 2) 不,你不能。 ISO 8601 明确表示零偏移量仅适用于 Z
  • 在您的符号SS.SSS 中,它是毫秒而不是微秒。但是你可以使用任何你喜欢的分数
  • 这完全取决于程序中的代码是如何工作的。您是否有权访问程序的代码,我们可以查看它是否使用SimpleDateFormat,如果是,那么字符串是什么?无论如何,2016-06-01T11:33:54.000Z2016-06-01T12:33:54.000+01:00 都是正确的,因为它们是同一时间点!对其中一个的偏好完全取决于您的程序和您正在处理的问题域(您有规范吗?)。
  • 看起来你的程序总是会在 Zulu 中给出一个日期/时间,从互操作性的角度来看,这实际上是最好的情况(例如,如果你需要将日期/时间发送到另一个程序)但是从从 UI 的角度来看,输出很可能需要以某种方式进行本地化。
  • 随机仅供参考 - 您或许应该在 SimpleDateFormat 中使用 yyyy 而不是 YYYY。它们的含义不同,并且可能会在年底前破坏您的计划。学到了这个很难。保持安全!
【解决方案2】:

如果程序给出的当前时间是 2016-06-01T11:33:54.000Z , 程序错了吗?

格式正确且符合ISO 8601,但不代表欧洲/伦敦时间。在伦敦,in 2016,夏令时开始于 3 月 27 日星期日凌晨 1:00,结束于 10 月 30 日星期日凌晨 2:00,因此是一个日期- 在此期间欧洲/伦敦的时间表示应具有+01:00 小时的时区偏移量。最后的Z 指定Zulu 时间,这是UTC 时间,因此时区偏移量为+00:00 小时。对于欧洲/伦敦,同一时刻可以表示为2016-06-01T12:33:54+01:00

java.time

java.util 日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到java.timemodern date-time API*

甚至 Joda-Time 也不应该再使用了。请注意Home Page of Joda-Time中的以下注释

Joda-Time 是 Java 的事实上的标准日期和时间库 在 Java SE 8 之前。现在要求用户迁移到 java.time (JSR-310)。

java.time API 基于ISO 8601 和日期时间字符串,2016-06-01T11:33:54.000Z 可以解析为java.time.ZonedDateTimejava.time.OffsetDateTime,而不需要日期时间解析/格式化类型。

演示:

import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        ZonedDateTime zdt = ZonedDateTime.parse("2016-06-01T11:33:54.000Z");
        System.out.println(zdt);

        ZoneId zoneId = ZoneId.of("Europe/London");
        ZonedDateTime zdtInLondon = zdt.withZoneSameInstant(zoneId);
        System.out.println(zdtInLondon);
    }
}

输出:

2016-06-01T11:33:54Z
2016-06-01T12:33:54+01:00[Europe/London]

如何处理夏令时(DST)?

如前所述,日期时间字符串2016-06-01T11:33:54.000Z 也可以解析为java.time.OffsetDateTime,而不需要日期时间解析/格式化类型。然而,OffsetDateTime 被设计用于处理固定的时区偏移,而ZonedDateTime 被设计用于处理时区 因此它会自动处理 DST。如果需要,您可以使用ZonedDateTime#toOffsetDateTimeZonedDateTime 转换为OffsetDateTime

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSS z", Locale.ENGLISH);

        String strDateTime = "2016-03-01T11:33:54.000 Europe/London";
        ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
        System.out.println(zdt);

        strDateTime = "2016-06-01T11:33:54.000 Europe/London";
        zdt = ZonedDateTime.parse(strDateTime, dtf);
        System.out.println(zdt);
    }
}

输出:

2016-03-01T11:33:54Z[Europe/London]
2016-06-01T11:33:54+01:00[Europe/London]

请注意时区偏移如何自动从 Z 更改为 01:00 以反映 DST 更改。另一方面,

import java.time.OffsetDateTime;

public class Main {
    public static void main(String[] args) {
        String strDateTime = "2016-03-01T11:33:54.000+01:00";
        OffsetDateTime odt = OffsetDateTime.parse(strDateTime);
        System.out.println(odt);

        strDateTime = "2016-06-01T11:33:54.000+01:00";
        odt = OffsetDateTime.parse(strDateTime);
        System.out.println(odt);
    }
}

输出:

2016-03-01T11:33:54+01:00
2016-06-01T11:33:54+01:00

在这种情况下,您不谈论时区(例如欧洲/伦敦);相反,您谈论的是+01:00 小时的固定时区偏移量。

Trail: Date Time 了解有关现代日期时间 API 的更多信息。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 和 7 . 如果您正在为一个 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-15
    • 2019-11-09
    • 1970-01-01
    • 2011-10-23
    • 2021-06-06
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    相关资源
    最近更新 更多