如何在 Java 中获取 UTC 或 GMT 的当前日期和时间?

新手上路,请多包涵

当我创建一个新的 Date 对象时,它被初始化为当前时间,但在本地时区。我怎样才能得到格林威治标准时间的当前日期和时间?

原文由 Behrang 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.9k
2 个回答

java.util.Date 没有特定的时区,尽管它的值最常被认为与 UTC 相关。是什么让你认为它是当地时间?

准确地说:a java.util.Date 中的值是自 Unix 纪元以来的毫秒数,该纪元发生在 1970 年 1 月 1 日午夜,UTC。同样的纪元也可以在其他时区描述,但传统的描述是根据 UTC。由于它是自固定纪元以来的毫秒数,因此 java.util.Date 中的值在任何特定时刻在世界范围内都是相同的,无论当地时区如何。

我怀疑问题是你通过使用本地时区的日历实例显示它,或者可能使用 Date.toString() 也使用本地时区,或者 SimpleDateFormat 实例,默认情况下,它也使用本地时区。

如果这不是问题,请发布一些示例代码。

不过,我还是建议您使用 Joda-Time ,它提供了更清晰的 API。

原文由 Jon Skeet 发布,翻译遵循 CC BY-SA 3.0 许可协议

tl;博士

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.Datej.u.Calendarjava.text.SimpleDateFormat 与 Java 捆绑在一起的类是出了名的麻烦。 避开他们。 相反,使用这些合格的日期时间库之一:

java.time (Java 8)

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 格式 生成其值的字符串表示形式。该格式根据需要输出零、三、六或九位数字( millisecondsmicrosecondsnanoseconds )以表示秒的分数。

如果您想要更灵活的格式或其他附加功能,则为 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 中的日期时间类型表,包括现代的和传统的。


关于 java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参阅 Oracle 教程。并在 Stack Overflow 中搜索许多示例和解释。规范是 JSR 310

现在处于 维护模式Joda-Time 项目建议迁移到 java.time 类。

您可以直接与数据库交换 java.time 对象。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。不需要字符串,不需要 java.sql.* 类。

在哪里获取 java.time 类?

哪个 java.time 库与哪个版本的 Java 或 Android 一起使用的表格

ThreeTen-Extra 项目用附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如 IntervalYearWeekYearQuarter 等等


乔达时间

更新:现在处于 维护模式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();

国际标准化组织 8601

阅读有关 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 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏