当我创建一个新的 Date
对象时,它被初始化为当前时间,但在本地时区。我怎样才能得到格林威治标准时间的当前日期和时间?
原文由 Behrang 发布,翻译遵循 CC BY-SA 4.0 许可协议
当我创建一个新的 Date
对象时,它被初始化为当前时间,但在本地时区。我怎样才能得到格林威治标准时间的当前日期和时间?
原文由 Behrang 发布,翻译遵循 CC BY-SA 4.0 许可协议
Instant.now() // Capture the current moment in UTC.
生成一个字符串来表示该值:
Instant.now().toString()
2016-09-13T23:30:52.123Z
正如 Jon Skeet 的正确答案 所述,java.util.Date 对象 没有时区† 。但其 toString
实现在生成该日期时间值的 String 表示时应用 JVM 的默认时区。令天真的程序员感到困惑的是,日期 似乎 有时区,但实际上没有。
java.util.Date
, j.u.Calendar
和 java.text.SimpleDateFormat
与 Java 捆绑在一起的类是出了名的麻烦。 避开他们。 相反,使用这些合格的日期时间库之一:
Java 8 带来了一个优秀的新 java.time.* 包 来取代旧的 java.util.Date/Calendar 类。
获取 UTC/GMT 中的当前时间是一个简单的单行……
Instant instant = Instant.now();
那个 Instant
类是 java.time 中的基本构建块,代表 UTC 时间轴上的一个时刻,分辨率为 纳秒。
在 Java 8 中,当前时刻的捕获精度最高可达毫秒。 Java 9 带来了 Clock
的全新实现,以此类的完整纳秒级能力捕获当前时刻,具体取决于主机计算机时钟硬件的能力。
它是 toString
方法使用 一种特定的 ISO 8601 格式 生成其值的字符串表示形式。该格式根据需要输出零、三、六或九位数字( milliseconds 、 microseconds 或 nanoseconds )以表示秒的分数。
如果您想要更灵活的格式或其他附加功能,则为 UTC 本身( ZoneOffset.UTC
常数)应用零偏移量以获得 OffsetDateTime
。
OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC );
转储到控制台…
System.out.println( "now.toString(): " + now );
运行时…
now.toString(): 2014-01-21T23:42:03.522Z
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 旧 日期时间类,例如 java.util.Date
、 Calendar
和 SimpleDateFormat
。
要了解更多信息,请参阅 Oracle 教程。并在 Stack Overflow 中搜索许多示例和解释。规范是 JSR 310 。
现在处于 维护模式 的 Joda-Time 项目建议迁移到 java.time 类。
您可以直接与数据库交换 java.time 对象。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。不需要字符串,不需要 java.sql.*
类。
在哪里获取 java.time 类?
ThreeTen-Extra 项目用附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如 Interval
、 YearWeek
、 YearQuarter
等等。
更新:现在处于 维护模式 的 Joda-Time 项目建议迁移到 java.time 类。
使用 Joda-Time 3rd-party 开源免费库,只需一行代码即可获取当前日期时间。
Joda-Time 启发了 Java 8 中的新 java.time.* 类,但具有不同的体系结构。您可以在旧版本的 Java 中使用 Joda-Time。 Joda-Time 继续在 Java 8 中工作,并继续得到积极维护(截至 2014 年)。但是,Joda-Time 团队确实建议迁移到 java.time。
System.out.println( "UTC/GMT date-time in ISO 8601 format: " + new org.joda.time.DateTime( org.joda.time.DateTimeZone.UTC ) );
更详细的示例代码(Joda-Time 2.3)……
org.joda.time.DateTime now = new org.joda.time.DateTime(); // Default time zone.
org.joda.time.DateTime zulu = now.toDateTime( org.joda.time.DateTimeZone.UTC );
转储到控制台…
System.out.println( "Local time in ISO 8601 format: " + now );
System.out.println( "Same moment in UTC (Zulu): " + zulu );
运行时…
Local time in ISO 8601 format: 2014-01-21T15:34:29.933-08:00
Same moment in UTC (Zulu): 2014-01-21T23:34:29.933Z
有关执行时区工作的更多示例代码,请参阅 我 对类似问题的回答。
我建议您始终指定一个时区,而不是隐含地依赖 JVM 当前的默认时区(它可以随时更改!)。这种依赖似乎是日期时间工作中混淆和错误的常见原因。
调用时 now()
传递要分配的所需/预期时区。使用 DateTimeZone
类。
DateTimeZone zoneMontréal = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( zoneMontréal );
该类 对 UTC 时区保持不变。
DateTime now = DateTime.now( DateTimeZone.UTC );
如果您真的想使用 JVM 的当前默认时区,请进行显式调用,以便您的代码是自文档化的。
DateTimeZone zoneDefault = DateTimeZone.getDefault();
阅读有关 ISO 8601 格式的信息。 java.time 和 Joda-Time 都使用该标准的合理格式作为解析和生成字符串的默认格式。
†实际上,java.util.Date 确实 有一个时区,深埋在源代码层之下。对于大多数实际用途,该时区将被忽略。因此,作为速记,我们说 java.util.Date 没有时区。此外,隐藏的时区 不是 Date 的 toString
方法使用的时区;该方法使用 JVM 当前的默认时区。更有理由避免这个令人困惑的类并坚持使用 Joda-Time 和 java.time。
原文由 Basil Bourque 发布,翻译遵循 CC BY-SA 4.0 许可协议
15 回答7.2k 阅读
2 回答3.5k 阅读✓ 已解决
3 回答7.1k 阅读✓ 已解决
5 回答4.8k 阅读
3 回答5.3k 阅读
4 回答2.5k 阅读
2 回答2.4k 阅读✓ 已解决
java.util.Date
没有特定的时区,尽管它的值最常被认为与 UTC 相关。是什么让你认为它是当地时间?准确地说:a
java.util.Date
中的值是自 Unix 纪元以来的毫秒数,该纪元发生在 1970 年 1 月 1 日午夜,UTC。同样的纪元也可以在其他时区描述,但传统的描述是根据 UTC。由于它是自固定纪元以来的毫秒数,因此java.util.Date
中的值在任何特定时刻在世界范围内都是相同的,无论当地时区如何。我怀疑问题是你通过使用本地时区的日历实例显示它,或者可能使用
Date.toString()
也使用本地时区,或者SimpleDateFormat
实例,默认情况下,它也使用本地时区。如果这不是问题,请发布一些示例代码。
不过,我还是建议您使用 Joda-Time ,它提供了更清晰的 API。