来自ZonedDateTime UTC实例的Java日期和时间戳
我有一个java应用程序,我想在UTC中的时间。 目前,代码使用java.util.Date
和java.sql.Timestamp
的混合。 为了得到UTC的时间,我之前的程序员使用了:
对于日期:
Date.from(ZonedDateTime.now(ZoneOffset.UTC)).toInstant();
对于时间戳:
Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
但是我自己用这个代码运行了多个测试,这两行都返回当前日期/时间(在我当前的时区)。 从我读过的所有内容看来 ,Date / Timestamp没有zoneOffset值,但我找不到具体的声明。
无论如何要将timeZone(UTC)保留在Date或Timestamp对象中,还是需要进行一些重构并在整个应用程序中使用实际的ZonedDateTime对象? 此ZonedDateTime对象也将与sql的当前Timestamp对象兼容吗?
例:
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类之前,程序员现在取代了臭名昭着的旧的遗留日期时间类,如Date
, Calendar
, Timestamp
。
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::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
请注意,我们不需要您提到的ZonedDateTime
因为您说您只对UTC感兴趣。 Instant
对象始终为UTC。 这意味着您引用的原始代码:
Date.from(ZonedDateTime.now(ZoneOffset.UTC)).toInstant();
……可以简单地缩短为:
Date.from( Instant.now() ) ;
请注意, java.util.Date
也始终为UTC。 但是,不幸的是,它的toString
在生成String时隐式地应用了JVM的当前默认时区。 通过在Stack Overflow上搜索,您可以看到这种反特征不会产生混淆。
如果要通过区域挂钟时间的镜头查看Instant
对象的UTC值,请指定时区ZoneId
以获取ZoneDateTime
。
以continent/region
的格式指定适当的时区名称 ,例如America/Montreal
, Africa/Casablanca
或Pacific/Auckland
。 切勿使用3-4字母缩写,如CDT
或EST
或IST
因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId z = ZoneId.of( "America/Chicago" ); ZonedDateTime zdt = instant.atZone( z );
关于java.time
java.time框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧遗留日期时间类,如java.util.Date
, Calendar
和SimpleDateFormat
。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
要了解更多信息,请参阅Oracle教程 。 并搜索Stack Overflow以获取许多示例和解释。 规范是JSR 310 。
您可以直接与数据库交换java.time对象。 使用符合JDBC 4.2或更高版本的JDBC驱动程序 。 不需要字符串,不需要java.sql.*
类。
从哪里获取java.time类?
- Java SE 8 , Java SE 9 , Java SE 10 , Java SE 11及更高版本 – 带有捆绑实现的标准Java API的一部分。
- Java 9增加了一些小function和修复。
- Java SE 6和Java SE 7
- 许多java.timefunction都被反向移植到ThreeTen-Backport中的 Java 6和7。
- Android的
- 更高版本的Android捆绑java.time类的实现。
- 对于早期的Android(<26), ThreeTenABP项目采用ThreeTen-Backport (如上所述)。 请参见如何使用ThreeTenABP ….
ThreeTen-Extra项目使用其他类扩展了java.time。 该项目是未来可能添加到java.time的试验场。 您可以在这里找到一些有用的课程,如Interval
, YearWeek
, YearQuarter
等。
在Java中, Date
代表一个时间点。 它与时间戳无关。 当您调用Date
对象的toString()
方法时,它会将该时间转换为Platform的默认时间戳,例如,Follow将以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);
我创建了如下所示的SimpleJdbcUpdate类:
public class SimpleJdbcUpdate { private final JdbcTemplate jdbcTemplate; private DataSource dataSource; private String tableName; private final TableMetaDataContext tableMetaDataContext = new TableMetaDataContext(); Map propertyToColumnMap = new HashMap<>(); private boolean compiled; public SimpleJdbcUpdate(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); this.dataSource = dataSource; } private List getColumnNames() { return Collections.emptyList(); } private String[] getGeneratedKeyNames() { return new String[0]; } public SimpleJdbcUpdate withTableName(String tableName) { this.tableName = tableName; return this; } public int execute(BeanPropertySqlParameterSource parameterSource, String[] keys) { if (!compiled) { compile(); } return doExecute(parameterSource, keys); } private int doExecute(BeanPropertySqlParameterSource parameterSource, String[] keys) { String[] propertyNames = parameterSource.getParameterNames(); List