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

Java 了解特定UTC时间格式YYYY-MM-DDTHH:MM:SS.SSSZ,java,utc,iso8601,gmt,Java,Utc,Iso8601,Gmt,我有两个相关的问题 假设在BST中运行的程序以UTC YYYY-MM-DDTHH:MM:SS.SSSZ格式为当前时间生成日期时间值 同时假设伦敦的当前时间为2016-06-01 12:33:54 如果程序给出的当前时间为2016-06-01T11:33:54.000Z,程序是否错误 在YYYY-MM-DDTHH:MM:SS.SSSZ的相应时间格式中,如何记录BST的夏季偏移量 我假设YYYY-MM-DDTHH:MM:SS+0001我是否正确?首先请阅读iso8601信息。处理不同时区(例如服

我有两个相关的问题

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

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

  • 如果程序给出的当前时间为2016-06-01T11:33:54.000Z,程序是否错误

  • 在YYYY-MM-DDTHH:MM:SS.SSSZ的相应时间格式中,如何记录BST的夏季偏移量


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

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

    请特别阅读UTC或“祖鲁”时间

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

  • 尾随的“Z”是UTC(Zulu)的简短符号。你也可以写“+00:00”而不是“Z”。SS.SSS指秒和毫秒-与时区无关。在devnull的评论中,他向您展示了如何为夏季应用补偿

  • 编辑

    评论中对iso8601时区是否包含时区以及时区是否会被打印出来进行了一些讨论

    这完全取决于实施的日期/时间。如果我们使用的是
    SimpleDataFormat
    ,则支持时区并将打印出来

    下面是一个代码示例

    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连年-除非它打算使用week year-在对类似问题的另一个回答中进行了详细解释

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

    格式正确且符合,但不代表欧洲/伦敦时间。在伦敦,DST开始于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
    date-time API及其格式化API
    SimpleDataFormat
    已经过时,并且容易出错。建议完全停止使用它们,并切换到
    java.time
    ,即*

    即使是Joda Time也不应再使用。请注意下面的注释

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

    java.time
    API基于
    ISO 8601
    和日期时间字符串,
    2016-06-01T11:33:54.000Z
    可以解析为
    java.time.ZonedDateTime
    java.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]
    
    2016-03-01T11:33:54Z[Europe/London]
    2016-06-01T11:33:54+01:00[Europe/London]
    
    2016-03-01T11:33:54+01:00
    2016-06-01T11:33:54+01:00
    
    输出:

    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]
    
    2016-03-01T11:33:54Z[Europe/London]
    2016-06-01T11:33:54+01:00[Europe/London]
    
    2016-03-01T11:33:54+01:00
    2016-06-01T11:33:54+01:00
    
    如何处理夏令时(DST)? 如前所述,日期时间字符串
    2016-06-01T11:33:54.000Z
    也可以解析为
    java.time.OffsetDateTime
    ,而无需日期时间解析/格式化类型。然而,
    OffsetDateTime
    被设计用于处理固定的时区偏移,而
    zoneDateTime
    被设计用于处理时区,因此它会自动处理DST。如果需要,可以使用将
    ZonedDateTime
    转换为
    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);
        }
    }
    
    输出:

    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]
    
    2016-03-01T11:33:54Z[Europe/London]
    2016-06-01T11:33:54+01:00[Europe/London]
    
    2016-03-01T11:33:54+01:00
    2016-06-01T11:33:54+01:00
    
    请注意,时区偏移是如何自动从
    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);
        }
    }
    
    输出:

    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]
    
    2016-03-01T11:33:54Z[Europe/London]
    2016-06-01T11:33:54+01:00[Europe/London]
    
    2016-03-01T11:33:54+01:00
    2016-06-01T11:33:54+01:00
    
    在这种情况下,您不谈论时区(例如欧洲/伦敦);相反,您谈论的是固定时区偏移量
    +01:00
    小时

    了解有关现代日期时间API的更多信息


    *无论出于何种原因,如果您必须坚持使用Java6或Java7,您可以使用哪个backport将大部分Java.time功能移植到Java6&7。如果您正在为Android项目工作,并且您的Android API级别仍然不符合Java-8,请检查并确认。

    1)没有,因为存在夏季补偿。UTC不随夏季偏移量变化。2) YYYY-MM-DDTHH:MM:SS+01:00那么上面例子中程序给出的时间应该是2016-06-01T11:33:54.000+01:00,你是说?不应该是
    2016-06-01T11:33:54.000Z
    或者
    2016-06-01T12:33:54.000+01:00
    或者
    2016-06-01T13:33:54.000+02:00
    什么都行!!这有帮助。2)不,你不能。ISO 8601明确指出零偏移量仅为
    Z
    。在您的符号中
    SS.SSS
    是毫秒而不是微秒。但是你可以使用任何你喜欢的分数,这完全取决于程序中代码的工作方式。您是否可以访问该程序的代码,我们是否可以查看它是否使用了
    SimpleDataFormat
    ,如果是,字符串是什么?在任何情况下,
    2016-06-01T11:33:54.000Z
    2016-06-01T12:33:54.000+01:00
    都是正确的,因为它们是相同的时间点!对一个或另一个的偏好完全取决于您的程序和您正在处理的问题域(您有规范吗?)。看起来您的程序总是以祖鲁语和