来自 ZonedDateTime UTC 实例的 Java 日期和时间戳tl;博士使用 java.time关于 java.time

2022-09-02 08:53:28

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

对于日期:

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

对于时间戳:

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

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

是否无论如何都要将时区 (UTC) 保留在 Date 或 Timestamp 对象中,或者我是否需要在整个应用程序中执行一些重构并使用实际的 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

答案 1

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.DateInstant

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

京东

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

符合 JDBC 4.2 的驱动程序可能能够通过调用 PreparedStatement::setObject 和 ResultSet::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

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

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

...可以简单地缩短为:

Date.from( Instant.now() ) ;

请注意,这也始终采用 UTC 格式。但是,不幸的是,它在生成字符串时隐式应用了JVM的当前默认时区。这种反功能不会造成无休止的混乱,您可以通过搜索Stack Overflow来查看。java.util.DatetoString

如果要通过区域的挂钟时间查看对象的 UTC 值,请指定一个时区以获取 .InstantZoneIdZoneDateTime

以 的格式指定适当的时区名称,例如 美国/蒙特利尔非洲/卡萨布兰卡或 。切勿使用3-4个字母的缩写,例如or或,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。continent/regionPacific/AucklandCDTESTIST

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

Table of date-time types in Java (both legacy and modern) and in standard SQL


关于 java.time

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

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


答案 2

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

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);