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

14

在Java中,当我使用Calendar.getInstance();时,会得到一个代表当前时区的Calendar对象。但是,java.sql.Timestamp通常存储在UTC时间而不是本地时间。那么,我应该如何从Calendar实例中获取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);
4个回答

18
当你调用Calendar.getTime()方法时,会返回一个没有关联时区的值,或者可以认为它位于UTC中,表示日历所代表的瞬间。因此,如果在日历所在的时区是上午9点,那么在UTC时间可能是下午5点。
现在,当你调用toString()方法(无论是隐式还是显式)对java.util.Date(我想也包括Timestamp)进行格式化输出时,它将使用系统默认时区进行格式化,但不要让这误导你以为时区是对象本身数据的一部分。
你需要非常清楚地了解你要实现的目标——然后你很可能会发现Joda Time比内置库更能清晰地在代码中表达它。

我实际上从一个API中获取了一个Calendar实例,然后我必须从中获取UTC时间戳。我喜欢Joda Time,但我不能在这里使用它。 - Jonas
@Jonas:好的,那么你只需要使用 getTime() - 这将给你一个UTC时间戳。 - Jon Skeet

12

你的代码已经完全按照你所期望的方式运行。 Timestamp (以及 Date )不包含时区信息,应始终包含格林威治标准时间戳(这是 Calendar.getTimeInMillis() 返回的内容)。

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


好的,有没有办法让 DateFormat 显示为 GMT 时间? - Jonas
@Jonas:DateFormat有一个setTimeZone()方法。 - Michael Borgwardt

5

简而言之

Instant.now() 

避免使用旧版日期时间类

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

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

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

使用 java.time

获取当前时刻作为一个 InstantInstant 类表示一个时间线上的时刻,以 UTC 为基准,分辨率为 纳秒(最多九位小数)。

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。您可以从Instant中提取该数字。但请注意数据丢失,因为Instant的分辨率为纳秒,您将截断为毫秒。

long millis = instant.toEpochMilli() ;

1487302155725


关于java.time

java.time框架是Java 8及更高版本中内置的。这些类取代了旧的、令人头疼的legacy日期时间类,如java.util.DateCalendarSimpleDateFormat

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

想要了解更多,请参见Oracle教程。同时,在Stack Overflow上搜索许多示例和解释。规范是JSR 310

在哪里获取java.time类?

这个 ThreeTen-Extra 项目扩展了 java.time 的附加类。该项目是 java.time 可能未来增加内容的试验场。您可能会在此处找到一些有用的类,例如 IntervalYearWeekYearQuarter更多

3
以下代码片段应该符合您的要求:
df.setTimeZone(TimeZone.getTimeZone("UTC"));

我刚刚修改了您的答案格式,没有给您点踩。 - j2ko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接