【问题标题】:How do I get a UTC Timestamp from Calendar?如何从日历中获取 UTC 时间戳?
【发布时间】: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);

【问题讨论】:

    标签: java localization calendar timezone timestamp


    【解决方案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:00Zepoch 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 类?

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

    【讨论】:

      猜你喜欢
      • 2014-11-21
      • 1970-01-01
      • 2019-05-02
      • 1970-01-01
      • 2018-01-17
      • 2012-11-11
      • 2013-03-20
      • 2016-03-25
      • 1970-01-01
      相关资源
      最近更新 更多