Calendar.getInstance().getTime() 在“GMT"中返回日期而不是默认时区

2022-01-11 00:00:00 calendar java gettime
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
c.set(2007, 0, 1);
System.out.println(c.getTime());

输出:

2017 年 9 月 12 日星期二 12:36:24 IST

Tue Sep 12 12:36:24 IST 2017

2007 年 1 月 1 日星期一 12:36:24 IST

Mon Jan 01 12:36:24 IST 2007

但是,当我在不同的环境中使用相同的代码时,输​​出变为以下:

But, When I use the same code in a different environment, Output changes to below:

输出:

2017 年 9 月 12 日星期二 12:36:24 IST

Tue Sep 12 12:36:24 IST 2017

格林威治标准时间 2007 年 1 月 1 日星期一 12:36:24

Mon Jan 01 12:36:24 GMT 2007

仅供参考,我尝试在设置值之前和之后打印日历实例的时区,并且两者都在IST"中.

FYI, I tried to print the timezone of the calendar instance, before and after setting the values and both are in "IST".

我想知道造成这种情况的根本原因.

I want to know the root cause of this.

推荐答案

您问题中的第二个输出是运行爱尔兰时间(欧洲/都柏林)的 JVM 上的正确和预期行为.2017 年 9 月 12 日,爱尔兰处于夏令时 (DST).虽然没有明确记录,但 Date.toString() (您在打印从 c.getTime() 获得的 Date 时隐式调用) 打印 JVM 时区中的日期和时间,该时区在 9 月呈现为爱尔兰夏令时的 IST.

The second output in your question is the correct and expected behaviour on a JVM running Irish time (Europe/Dublin). On September 12, 2017 Ireland is on summer time (DST). While it is not clearly documented, Date.toString() (which you invoke implicitly when printing the Date you get from c.getTime()) prints the date and time in the JVM’s time zone, which in September is rendered as IST for Irish Summer Time.

当您在 Calendar 对象上同时使用爱尔兰时间设置日期时,会保留一天中的小时;在您的情况下,您将获得 2007 年 1 月 1 日 12:36:24 爱尔兰标准时间.现在想象一下,如果爱尔兰夏令时间和爱尔兰标准时间都被呈现为 IST,会造成什么混乱.你将无法区分.相反,由于爱尔兰标准时间与格林威治标准时间重合,当日期在一年中的夏季时间部分(即 1 月是't).

When you set the date on the Calendar object also using Irish time, the hour of day is preserved; in your case you get Jan 01 2007 12:36:24 Irish standard time. Now imagine the confusion if both Irish Summer Time and Irish Standard Time were rendered as IST. You would not be able to distinguish. Instead, since Irish standard time coincides with GMT, this is what Date.toString() prints when the date is not in the summer time part of the year (which January isn’t).

我的猜测是您的第一个输出来自运行印度时间的 JVM.它也被呈现为 IST,并且由于印度不使用夏令时,因此夏季和冬季使用相同的缩写.

My guess is that your first output is from a JVM running India time. It too is rendered as IST, and since India doesn’t use summer time, the same abbreviation is given summer and winter.

在理解您观察到的行为的解释之前,我发布了关于过时和现代 Java 日期和时间类的评论.不过,我仍然不认为评论是错误的.这是您的代码的现代等价物:

Before understanding the explanation for the behaviour you observed, I posted a comment about the outdated and the modern Java date and time classes. I still don’t think the comment is way off, though. This is the modern equivalent of your code:

    ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Europe/Dublin"));
    System.out.println(zdt);
    zdt = zdt.with(LocalDate.of(2007, Month.JANUARY, 1));
    System.out.println(zdt);

打印出来

2017-09-12T11:45:33.921+01:00[Europe/Dublin]
2007-01-01T11:45:33.921Z[Europe/Dublin]

如果要使用 JVM 的时区设置,请使用 ZoneId.systemDefault() 而不是 ZoneId.of("Europe/Dublin").正如名称所述,与 Date 不同,ZonedDateTime 确实包含时区.它更多地对应于旧的 Calendar 类.如您所见,它的 toString 方法打印与 UTC 的偏移量(Z 表示零偏移量)和明确的 region/city 格式.我相信这会减少混乱的空间.如果要以特定格式打印日期,请使用 DateTimeFormatter.

If you want to use the JVM’s time zone setting, use ZoneId.systemDefault() instead of ZoneId.of("Europe/Dublin"). As the name states, contrary to Date, ZonedDateTime does include a time zone. It corresponds more to the old Calendar class. As you can see, its toString method prints the offset from UTC (Z meaning zero offset) and the time zone name in the unambiguous region/city format. I believe that this leaves a lot less room for confusion. If you want to print the date in a specific format, use a DateTimeFormatter.

为了完整起见,以下是您的代码在运行可能呈现为 IST 的不同时区时的输出:

For the sake of completeness, here are the outputs from your code when running different time zones that may be rendered as IST:

  • 欧洲/都柏林(同意您的第二个输出)

  • Europe/Dublin (agrees with your second output)

Tue Sep 12 11:19:28 IST 2017
Mon Jan 01 11:19:28 GMT 2007

  • 亚洲/特拉维夫

  • Asia/Tel_Aviv

    Tue Sep 12 13:19:28 IDT 2017
    Mon Jan 01 13:19:28 IST 2007
    

  • Asia/Kolkata(同意你的第一个输出)

  • Asia/Kolkata (agrees with your first output)

    Tue Sep 12 15:49:28 IST 2017
    Mon Jan 01 15:49:28 IST 2007
    

  • 相关文章