【问题标题】:Java Calendar Date still adding Time on UTC Date 00:00 [duplicate]Java日历日期仍在UTC日期00:00添加时间[重复]
【发布时间】:2018-06-03 22:50:36
【问题描述】:

我将日历实例设置为 00:00 的 UTC 日期,但是一旦我提前 1 小时返回结果

Calendar cal = Calendar.getInstance(TIMEZONE_UTC, Locale.ENGLISH);
cal.set(2017, 12 - 1, 15);
cal.set(Calendar.AM_PM, Calendar.AM);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
System.out.println(cal.getTime());
// Fri Dec 15 01:00:00 CET 2017 but should be 00:00:00

我想有冬季/夏季偏移,但我没有在公历或日历元素中找到任何描述来处理这个问题

【问题讨论】:

  • 你得到的时间是正确的,00:00:00 UTC。愚弄您的是Date.toString()(从System.out.println() 隐式调用)正在将生成的字符串的时间转换为您自己的时区(使用JVM 时区设置)。
  • 我建议你停止使用早已过时的Calendar 类。 java.time, the modern Java date and time API,使用起来更好。并且使用现代 API 中的ZonedDateTime(或OffsetDateTimeInstant)将解决您的问题。
  • 您是否希望这个日期的 UTC 午夜同时也是 CET 时区的午夜 (00:00:00)?不可能,因为对于那个特定的未识别区域,CET 在那个日期比 UTC 早一个小时。我说不明是因为 CET 不是时区,而是时区的影响,例如Europe/London
  • 简而言之:该日期 00:00:00 UTC 01:00:00 CET。

标签: java java-calendar


【解决方案1】:

我的印象是,您真的只是在 2017 年 12 月 15 日之后,只是想确保一天中没有意外的时间?如果是这样,来自java.timeLocalDate(现代Java 日期和时间API)就是为您准备的:

LocalDate ld = LocalDate.of(2017, Month.DECEMBER, 15);
System.out.println(ld);

打印出来

2017-12-15

无需担心小时、分钟或秒。

如果您确实需要 00:00 UTC 的日期时间(我过去常常调用午夜直到 Basil Bourque’s comment),有几种方法可以获得它。其中之一是:

    OffsetDateTime utcDateTime = LocalDateTime.of(2017, Month.DECEMBER, 15, 0, 0)
            .atOffset(ZoneOffset.UTC);
    System.out.println(utcDateTime);

打印出来

2017-12-15T00:00Z

最后的Z 表示UTC 或偏移量为零。您会看到一天中的时间是您想要的 00:00。

你在问题​​中使用的Calendar 类已经过时了,所以我建议你不要再使用它了。 java.time,现代 Java 日期和时间 API,也称为 JSR-310,使用起来更方便。

你的代码出了什么问题?

虽然Calendar 确实包含时区(您将其初始化为TIMEZONE_UTC),但Date(另一个过时的类)却没有。因此,当您使用 cal.getTime() 转换为 Date 时,您会丢失您希望时间为 UTC 的信息。接下来(这让很多人感到困惑),当您打印日期时,您隐式调用Date.toString(),并且此方法获取您的 JVM 的时区设置并生成一个包含该时区时间的字符串。显然,您(和我一样)处于 12 月 UTC+01:00 的时区。以下两个日期时间表示时间轴上的相同点:

Fri Dec 15 01:00:00 CET 2017
Fri Dec 15 00:00:00 UTC 2017

【讨论】:

  • 好答案,但我建议使用“一天中的第一刻”而不是“午夜”。 “午夜”一词是无定形的,在不同的情况下对不同的人意味着不同的事情。请注意,Joda-Time 项目在删除概念和术语方面取得了重大突破,并弃用了几个类,而是在术语和类中都采用了“一天开始”的概念。
  • 谢谢,@BasilBourque,已编辑。
【解决方案2】:

您看到打印本地时间的原因是您通过使用本地时区(隐式使用系统时区)的Date.toString() 的日历实例显示它。

【讨论】:

  • 这是不正确的,与问题的语义不同。问题将Calendar 对象设置为UTC 中的00:00:00,然后在调用Calendar::getTime 时实例化一个Date,该Date 没有适用的时区(始终为UTC),但其Date::toString 动态应用JVM 的当前默认值时区,必须比 UTC 早一小时的时区之一。相比之下,此答案将 Calendar 对象设置为 BST(伦敦时间)的 00:00:00,完全不同的时刻,比问题中的时刻早一个小时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-19
  • 2013-07-12
  • 2017-04-12
  • 1970-01-01
  • 2018-07-31
相关资源
最近更新 更多