【问题标题】:Java.util.Date: try to understand UTC and ET moreJava.util.Date:尝试更多地了解 UTC 和 ET
【发布时间】:2011-08-23 10:08:18
【问题描述】:

顺便说一句,我住在东区的北卡罗来纳州。所以我编译并运行这段代码,它打印出同样的东西。文档说 java.util.date 尝试反映 UTC 时间。

Date utcTime = new Date();
Date estTime = new Date(utcTime.getTime() + TimeZone.getTimeZone("ET").getRawOffset());
DateFormat format = new SimpleDateFormat("dd/MM/yy h:mm a");
System.out.println("UTC: " + format.format(utcTime));
System.out.println("ET: " + format.format(estTime));   

这就是我得到的

UTC: 11/05/11 11:14 AM
ET: 11/05/11 11:14 AM

但是如果我去这个website 试图反映所有不同的时间,UTC 和 ET 是不同的。我在这里做错了什么

【问题讨论】:

    标签: java date timezone


    【解决方案1】:

    根据this post,你可以写TimeZone.getTimeZone("ETS")而不是TimeZone.getTimeZone("ET")

    【讨论】:

      【解决方案2】:

      TimeZone.getTimeZone("ET").getRawOffset() 返回 0 这就是原因

      【讨论】:

        【解决方案3】:

        那是因为 getRawOffset() 返回 0 - 它也为“ET”对我执行此操作,实际上 TimeZone.getTimeZone("ET") 基本上返回 GMT。我怀疑这不是你的意思。

        我相信北卡罗来纳州最好的奥尔森时区名称是“America/New_York”。

        请注意,您不应该只将时区的原始偏移量添加到 UTC 时间 - 您应该设置格式化程序的时区。 Date 值并不真正了解时区...自 1970 年 1 月 1 日 UTC 以来,它始终只是毫秒。

        所以你可以使用:

        导入 java.text.; 导入 java.util.;

        Date date = new Date();
        DateFormat format = new SimpleDateFormat("dd/MM/yy h:mm a zzz");
        
        format.setTimeZone(TimeZone.getTimeZone("America/New_York"));
        System.out.println("Eastern: " + format.format(date));
        
        format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        System.out.println("UTC: " + format.format(date));
        

        输出:

        Eastern: 11/05/11 11:30 AM EDT
        UTC: 11/05/11 3:30 PM UTC
        

        我还建议您现在考虑使用 java.time - 这比 java.util 类好得多。

        【讨论】:

        • 我还有一个关于时间的问题。 stackoverflow.com/questions/5968842/… 。你认为你也可以帮助我吗?
        • 我想强调一下关于内置库的建议并不实际。现在我们在标准 JDK 库中有了可爱的 java.time API。
        • @turbanoff:“不实际”是指“10 年后不再合适”吗? (我已经编辑了答案,但我真的不能期望我的 35,000 多个答案中的每一个都是最新的......)
        【解决方案4】:

        您要查找的时区是"EST""EDT"(夏令时),而不是"ET"。见http://mindprod.com/jgloss/timezone.html

        【讨论】:

          【解决方案5】:

          东部标准时间的正确缩写是“EST”,而不是“ET”。看起来getRawOffset() 方法在传递未知时区时返回 0。

          TimeZone.getTimeZone("EST").getRawOffset()
          

          此外,当您输出 utcTime 变量时,您不会输出 UTC 时间。您正在输出 EST 时间,因为您住在那个时区。据我了解,Date 类在内部以 UTC 格式存储时间......但是当您对其进行格式化以便将其输出为人类可读的字符串时,它会考虑当前的语言环境/时区。

          【讨论】:

            【解决方案6】:

            不知不觉中,您在代码中引入了两个主要问题

            1. 未使用正确的时区名称:两个/三个/四个字母的时区名称(例如 ET、EST、CEST 等)容易出错。 proper way of naming a timezoneRegion/City 例如欧洲/伦敦。在大多数情况下,RegionCity 所属大陆的名称。
            2. 不使用 LocaleSimpleDateFormat:解析/格式化类型,例如旧版SimpleDateFormat 或现代版DateTimeFormatterLocale 敏感,因此您应该始终使用Locale 以避免意外。您可以查看this answer 了解更多信息。

            另外,请注意java.util.Date 对象不是像modern Date-Time types 那样的真实日期时间对象;相反,它表示自称为“纪元”的标准基准时间以来的毫秒数,即January 1, 1970, 00:00:00 GMT(或 UTC)。由于它不包含任何格式和时区信息,它应用格式 EEE MMM dd HH:mm:ss z yyyy 和 JVM 的时区来返回从该毫秒值派生的 Date#toString 的值。如果您需要以不同的格式和时区打印日期时间,则需要使用具有所需格式和适用时区的SimpleDateFormat,例如

            import java.text.SimpleDateFormat;
            import java.util.Date;
            import java.util.Locale;
            import java.util.TimeZone;
            
            public class Main {
                public static void main(String[] args) {
                    Date date = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yy hh:mm a zzz", Locale.ENGLISH);
            
                    sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
                    System.out.println(sdf.format(date));
            
                    sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
                    System.out.println(sdf.format(date));
                }
            }
            

            示例输出:

            05/06/21 08:29 AM EDT
            05/06/21 12:29 PM UTC
            

            ONLINE DEMO

            java.time

            java.util 日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用,改用modern Date-Time API*

            使用现代 API java.time 的演示:

            import java.time.Instant;
            import java.time.ZoneId;
            import java.time.ZonedDateTime;
            
            public class Main {
                public static void main(String[] args) {
                    Instant now = Instant.now();
                    System.out.println(now);
            
                    ZonedDateTime zdtUTC = now.atZone(ZoneId.of("Etc/UTC"));
                    System.out.println(zdtUTC);
            
                    ZonedDateTime zdtNewYork = now.atZone(ZoneId.of("America/New_York"));
                    System.out.println(zdtNewYork);
                }
            }
            

            示例输出:

            2021-06-05T12:19:58.092338Z
            2021-06-05T12:19:58.092338Z[Etc/UTC]
            2021-06-05T08:19:58.092338-04:00[America/New_York]
            

            ONLINE DEMO

            需要不同格式的输出字符串?

            您可以将DateTimeFormatter 用于不同格式的输出字符串,例如

            import java.time.Instant;
            import java.time.ZoneId;
            import java.time.ZonedDateTime;
            import java.time.format.DateTimeFormatter;
            import java.util.Locale;
            
            public class Main {
                public static void main(String[] args) {
                    Instant now = Instant.now();
                    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/MM/uu hh:mm a zzz", Locale.ENGLISH);
            
                    ZonedDateTime zdtUTC = now.atZone(ZoneId.of("Etc/UTC"));
                    System.out.println(dtf.format(zdtUTC));
            
                    ZonedDateTime zdtNewYork = now.atZone(ZoneId.of("America/New_York"));
                    System.out.println(dtf.format(zdtNewYork));
                }
            }
            

            示例输出:

            05/06/21 12:34 PM UTC
            05/06/21 08:34 AM EDT
            

            ONLINE DEMO

            在这里,您可以使用yy 代替uu,但可以使用I prefer u to y

            Trail: Date Time了解更多关于java.timemodern 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
              • 2011-06-15
              • 2020-01-04
              • 1970-01-01
              • 2019-10-04
              • 1970-01-01
              • 2022-01-23
              • 2019-06-18
              • 2018-11-22
              相关资源
              最近更新 更多