了解特定的UTC时间格式YYYY-MM-DDTHH:MM:SS.SSSZ

时间:2016-06-02 10:48:22

标签: java utc iso8601 gmt

我有两个相关问题。

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

另请假设伦敦当前时间为2016-06-01 12:33:54

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

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

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

2 个答案:

答案 0 :(得分:8)

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

特别请阅读UTC或“Zulu”时间here

1)该计划是正确的,因为伦敦时间比夏季的“UTC”时间提前一小时

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

修改

评论中有一些关于iso8601时区是否包含时区的讨论,以及时区是否实际打印出来。

这完全取决于日期/时间的实施。如果我们使用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,则实施细节会有所不同。

答案 1 :(得分:1)

<块引用>

如果程序给出的当前时间是 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 旨在处理 时区,因此它会自动处理夏令时。如果需要,您可以使用 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