如何从日历中获取 UTC 时间戳?

Posted

技术标签:

【中文标题】如何从日历中获取 UTC 时间戳?【英文标题】:How do I get a UTC Timestamp from Calendar? 【发布时间】:2011-05-21 14:35:31 【问题描述】:

在 Java 中,当我使用 Calendar.getInstance(); 时,我得到了当前时区的 Calendar 对象。但是java.sql.Timestamp 通常存储在UTC 时间而不是本地时间。那么如何从日历实例中获取 UTC 时间呢?

    DateFormat df = DateFormat.getTimeInstance();
    Calendar cal = Calendar.getInstance();
    Timestamp time = new Timestamp(cal.getTimeInMillis());

    // Prints local time
    System.out.println(df.format(new Date(time.getTime())));

    // Printe local time, but I want UTT Time
    System.out.println("timestamp: " + time);

【问题讨论】:

【参考方案1】:

当您调用 Calendar.getTime() 时,这将为您提供一个没有相关时区的值 - 或者您可以将其视为 UTC - 对于日历的 即时代表。因此,如果是(例如)日历所在时区的上午 9 点,则可能是世界标准时间下午 5 点。

现在java.util.Date(我想Timestamp)将在您调用toString()(无论是隐式还是显式)时在系统默认时区格式化 - 但不要让你误以为时区是对象本身数据的一部分。

您需要非常清楚确切地要达到的目标 - 然后您可能会发现 Joda Time 可以让您在代码中比内置代码更清楚地表达这一点图书馆可以。

【讨论】:

我实际上从 API 获得了一个 Calendar 实例,然后我必须从中获得 UTC 时间戳。我喜欢 Joda Time,但我不能在这里使用它。 @Jonas:好的,在这种情况下,您只需要使用getTime() - 这将为您提供 UTC 时间戳。【参考方案2】:

您的代码已经完全按照您的意愿行事。 Timestamp(以及 Date)没有时区信息,并且应该始终包含 GMT 时间戳(这是 Calendar.getTimeInMillis() 返回的内容)。

您看到打印本地时间的原因是 DateFormat 工厂方法以及 Timestamp.toString() 隐式使用系统时区。

【讨论】:

好的,有什么办法可以让DateFormat在格林威治时间显示? @Jonas:DateFormat 有一个 setTimeZone() 方法【参考方案3】:

以下 sn-p 应该可以满足您的要求:

df.setTimeZone(TimeZone.getTimeZone("UTC"));

【讨论】:

我刚刚格式化了你的答案,并没有投反对票。【参考方案4】:

tl;博士

Instant.now() 

避免使用旧的日期时间类

您正在使用麻烦的旧日期时间类,现在已被 java.time 类取代。无需使用DateFormatCalendarTimestamp

如果您必须与尚未更新到 java.time 的旧代码中的 Calendar 进行交互,请使用添加到旧类的新方法进行转换。提取一个过时的java.util.Date,并转换为Instant

Instant instant = myCal.getTime().toInstant() ;

使用 java.time

Instant 的形式获取当前时刻。 Instant 类代表UTC 时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。

Instant instant = Instant.now() ;

2017-02-17T03:29:15.725Z

数据库

使用 JDBC 4.2 及更高版本,您可以直接与您的数据库交换 Instant 对象。所以不需要过时的java.sql.Timestamp

myPreparedStatement.setObject( … , instant ) ;

及检索:

Instant instant = myResultSet.getObject( … , Instant.class ) ;

从纪元开始计数

显然你想要从1970-01-01T00:00:00Z 的epoch reference date 开始的毫秒数。您可以从Instant 中提取该号码。但请注意数据丢失,因为Instant 的分辨率为纳秒,您将截断为毫秒。

long millis = instant.toEpochMilli() ;

1487302155725


关于java.time

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

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。

从哪里获得 java.time 类?

Java SE 8SE 9 及更高版本 内置。 标准 Java API 的一部分,带有捆绑实现。 Java 9 添加了一些小功能和修复。 Java SE 6SE 7 大部分 java.time 功能在ThreeTen-Backport 中向后移植到 Java 6 和 7。 Android ThreeTenABP 项目专门针对 android 改编了 ThreeTen-Backport(如上所述)。 见How to use ThreeTenABP…

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

【讨论】:

以上是关于如何从日历中获取 UTC 时间戳?的主要内容,如果未能解决你的问题,请参考以下文章

已更新如何在 JavaScript 中获取 UTC 时间戳?

无法从 iOS 中的 firebase 获取时间戳?

php获取UTC时间戳

在 Lua 中获取 UTC UNIX 时间戳

给定 UTC 时间戳和 UTC 偏移量,是不是可以在 Python 中获取时区?

使用 node-postgres 在 utc 中获取 Postgres“没有时区的时间戳”