繁体   English   中英

来自 ZonedDateTime UTC 实例的 Java 日期和时间戳

[英]Java Date and Timestamp from instance of ZonedDateTime UTC

我有一个 Java 应用程序,我希望在其中使用 UTC 时间。 目前,该代码混合使用java.util.Datejava.sql.Timestamp 为了获得UTC时间,我之前的程序员使用:

日期:

 Date.from(ZonedDateTime.now(ZoneOffset.UTC)).toInstant();

对于时间戳:

 Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());

但是,我自己使用此代码运行了多个测试,这两行都返回当前日期/时间(在我当前的时区)。 从我读过的所有内容来看,日期/时间戳似乎没有 zoneOffset 值,但我找不到具体的说明。

无论如何要在 Date 或 Timestamp 对象中保留 timeZone (UTC),或者我是否需要进行一些重构并在整个应用程序中使用实际的 ZonedDateTime 对象? 这个 ZonedDateTime 对象是否与当前的 sql 时间戳对象兼容?

例子:

public static void main (String args[])
{
    ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
    Timestamp timestamp = Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
    Date date = Date.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
    System.out.println("ZonedDateTime: " + zonedDateTime);
    System.out.println("Timestamp: " + timestamp);
    System.out.println("Date: " + date);
}

输出:

 ZonedDateTime: 2017-04-06T15:46:33.099Z
 Timestamp: 2017-04-06 10:46:33.109
 Date: Thu Apr 06 10:46:33 CDT 2017

tl;博士

Instant.now()  // Capture the current moment in UTC with a resolution up to nanoseconds.

仅使用java.time类。 避免在 Java 8 之前添加的麻烦的旧的遗留日期时间类。

使用 java.time

您之前的程序员正在使用新的现代 java.time 类,这些类现在取代了臭名昭著的旧的遗留日期时间类,例如DateCalendarTimestamp

Instant

Instant类表示UTC时间轴上的一个时刻,分辨率为纳秒(最多九 (9) 位小数)。 获取 UTC 中的当前时刻非常简单: Instant.now

Instant instant = Instant.now();

转换

您应该坚持使用 java.time 类,并避免使用遗留类。 但如果绝对必要,例如与尚未为 java.time 更新的旧代码接口,您可以转换为/从 java.time。 寻找旧类的新方法。 旧类java.util.Date等效项是Instant

java.util.Date d = java.util.Date.from( myInstant); // To legacy from modern.
Instant instant = myJavaUtilDate.toInstant();  // To modern from legacy.

JDBC

避免使用旧的日期时间类。 改用 java.time 类。

您的JDBC 4.2兼容驱动程序可能能够通过调用PreparedStatement::setObjectResultSet::getObject直接处理 java.time 类型。

myPreparedStatement.setObject( … , instant ) ;

… 和 …

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

如果不是,请回退到使用 java.sql 类型,但要尽可能简短。 使用添加到旧类的新转换方法。

myPreparedStatement.setTimestamp( … , java.sql.Timestamp.from( instant ) ) ;

… 和 …

Instant instant = myResultSet.getTimestamp( … ).toInstant() ;

不需要ZonedDateTime

请注意,我们不需要您提到的ZonedDateTime因为您说您只对 UTC 感兴趣。 Instant对象始终采用 UTC。 这意味着您引用的原始代码:

Date.from(ZonedDateTime.now(ZoneOffset.UTC)).toInstant();

……可以简单地缩短为:

Date.from( Instant.now() ) ;

请注意, java.util.Date也始终采用 UTC。 然而,不幸的是,它的toString在生成字符串时隐式地应用了 JVM 的当前默认时区。 正如您可以通过在 Stack Overflow 上搜索看到的那样,此反功能会造成无休止的混乱。

如果您想通过区域挂钟时间的镜头查看Instant对象的 UTC 值,请分配时区ZoneId以获取ZoneDateTime

continent/region的格式指定正确的时区名称,例如America/MontrealAfrica/CasablancaPacific/Auckland 切勿使用 3-4 个字母的缩写,例如CDTESTIST因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Chicago" );
ZonedDateTime zdt = instant.atZone( z );

Java(旧版和现代版)和标准 SQL 中的日期时间类型表


关于java.time

java.time框架内置于 Java 8 及更高版本中。 这些类取代麻烦的老传统日期时间类,如java.util.DateCalendar ,和SimpleDateFormat

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

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

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

从哪里获得 java.time 类?

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

在 Java 中, Date代表一个时间点。 它与时间戳无关。 当您调用Date对象的toString()方法时,它会将该时间转换为平台的默认时间戳,例如以下将以 UTC 打印日期/时间(因为它将默认时区设置为 UTC):

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
Timestamp timestamp = Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
Date date = Date.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
System.out.println("ZonedDateTime: " + zonedDateTime);
System.out.println("Timestamp: " + timestamp);
System.out.println("Date: " + date);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM