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

来自ZoneDateTime UTC实例的Java日期和时间戳,java,sql,date,timestamp,Java,Sql,Date,Timestamp,我有一个java应用程序,我希望时间是UTC。目前,代码混合使用了java.util.Date和java.sql.Timestamp。为了获得UTC时间,我之前的程序员使用: 截止日期: Date.from(ZonedDateTime.now(ZoneOffset.UTC)).toInstant(); 对于时间戳: Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant()); 但是,我自己用这段代码运行了多个测试,这两行都返

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

截止日期:

 Date.from(ZonedDateTime.now(ZoneOffset.UTC)).toInstant();
对于时间戳:

 Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
但是,我自己用这段代码运行了多个测试,这两行都返回当前日期/时间(在我当前的时区)。从我所读到的一切来看,日期/时间戳似乎没有区域偏移值,但我找不到这方面的具体说明

是否要将时区(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

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

tl;博士 仅使用java.time类。避免在Java8之前添加麻烦的旧遗留日期时间类

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

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

Instant instant = Instant.now();
转换 您应该坚持使用java.time类,并避免使用遗留类。但是,如果绝对必要,例如与尚未更新为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类

您的compliant可以通过调用和直接寻址java.time类型

……还有

Instant instant = myResultSet.getObject( … , Instant.class ) ;
Instant instant = myResultSet.getTimestamp( … ).toInstant() ;
如果没有,请返回使用java.sql类型,但要尽可能简短。使用添加到旧类中的新转换方法

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

Instant instant = myResultSet.getObject( … , Instant.class ) ;
Instant instant = myResultSet.getTimestamp( … ).toInstant() ;
不需要
ZoneDateTime
请注意,我们不需要您提到的
ZoneDateTime
,因为您说您只对UTC感兴趣。
Instant
对象始终以UTC为单位。这意味着您引用的原始代码:

Date.from(ZonedDateTime.now(ZoneOffset.UTC)).toInstant();
…可以简单地缩短为:

Date.from( Instant.now() ) ;
请注意,
java.util.Date
也始终使用UTC。然而,它的
toString
不幸地在生成字符串时隐式地应用了JVM的当前默认时区。通过搜索堆栈溢出,您可以看到,此反功能带来了无尽的混乱

如果要通过区域的镜头查看对象的UTC值,请指定时区
ZoneId
,以获取
ZoneDateTime

大陆/地区
的格式指定,例如,或
太平洋/奥克兰
。切勿使用3-4个字母的缩写,如
CDT
EST
IST
,因为它们不是真正的时区,不标准化,甚至不是唯一的(!)



关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

您可以直接与数据库交换java.time对象。使用兼容的或更高版本。不需要字符串,也不需要
java.sql.*

从哪里获得java.time类

  • 、和更高版本-标准Java API的一部分,带有捆绑实现。
    • Java9添加了一些次要功能和修复
    • 大部分java.time功能都在中向后移植到Java6和Java7
    • 更高版本的Android捆绑包实现了java.time类

    • 对于早期的Android(“…返回当前日期/时间(在我当前的时区)…”,可能您刚刚使用了方法
      toString()
      java.util.Date
      上的
      得出结论,但此方法仅使用外部默认时区打印自身。偏移量或时区从来不是
      java.util.Date
      的一部分,其真实状态由方法
      getTime()反映
      。因此,请澄清您真正做了什么。日期和时间戳都以GMT存储时间。切换时区只会更改显示值。
      Date.from(ZonedDateTime.now(ZoneOffset.UTC.toInstant())和
      new Date()之间没有逻辑差异
      。除前者外,前者更容易混淆。通常我不建议查看源代码,因为类的行为是由其契约(javadoc)定义的,但从Java 8开始,它只有两个实例字段:一个长值和一个“BaseCalendar”对象,仅由现在已弃用的方法使用(可追溯到日历类不存在且date类试图提供所有与日历相关的功能时)。它只包装一个毫秒值;不保留时区信息。为什么建议使用
      setObject()
      而不是使用
      java.sql
      类型
      timestamp
      ?@mFeinstein,因为
      timestamp
      是一个糟糕的类设计的憎恶。java.time框架是由Sun、Oracle和JCP设计并采用的,以完全支持
      Date.from( Instant.now() ) ;
      
      ZoneId z = ZoneId.of( "America/Chicago" );
      ZonedDateTime zdt = instant.atZone( z );