如何将ZonedDateTime转换为date?

我想在我的数据库中设置一个服务器不可知的date时间,我相信最好的做法是设置一个UTCdate时间。 我的数据库服务器是Cassandra,Java的数据库驱动程序只能理解datetypes。

因此,假设在我的代码中,我正在使用新的Java 8 ZonedDateTime来获取UTC现在( ZonedDateTime.now(ZoneOffset.UTC) ),如何将此ZonedDateTime实例转换为“传统”date类?

您可以将ZoneDateTime转换为即时,您可以直接使用Date。

 Date.from(java.time.ZonedDateTime.now().toInstant()); 

TL;博士

 java.util.Date utilDate = java.util.Date.from ( myZonedDateTime.toInstant() ) ; // Caution: possible data loss. 

其他答案正确

ssoltanid的答案正确地解决了您的具体问题,如何将一个新的java.time对象( ZonedDateTime )转换为老派的java.util.Date对象。 从ZonedDateTime中提取Instant并传递给java.util.Date.from()

数据丢失

请注意,您将遭受数据丢失 ,因为Instant追踪自时代以来的纳秒 ,而java.util.Date追踪时代以来的毫秒数 。

图表比较毫秒,微秒和纳秒的分辨率

你的问题和意见提出了其他问题。

以UTC保持服务器

您的服务器应该将其主机操作系统设置为UTC,作为一般的最佳做法。 JVM在这个主机操作系统设置中select默认时区,在我知道的Java实现中。

指定时区

但是,您绝不应该依赖JVM当前的默认时区。 启动JVM时传递的标志可以设置另一个时区,而不是拾取主机设置。 更糟糕的是:任何时候任何应用程序的任何线程中的任何代码都可以调用java.util.TimeZone::setDefault在运行时更改默认值!

卡桑德拉Timestamptypes

任何体面的数据库和驱动程序都应该自动处理将通过的date时间调整为UTC以进行存储。 我不使用卡桑德拉,但它似乎对date时间有一些基本的支持。 该文档说,其Timestamptypes是从同一纪元(1970年的第一个时刻UTC)的毫秒数。

ISO 8601

此外,Cassandra接受ISO 8601标准格式的stringinput。 幸运的是,java.time使用ISO 8601格式作为parsing/生成string的默认值。 Instant类的toString实现将很好地完成。

精确度:毫秒与Nanosecord

但是首先我们需要将ZonedDateTime的纳秒精度降低到几毫秒。 一种方法是使用毫秒创build一个新的即时。 幸运的是,java.time有一些方便的方法来转换成毫秒。

示例代码

这里是Java 8 Update 60中的一些示例代码。

 ZonedDateTime zdt = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) ); … Instant instant = zdt.toInstant(); Instant instantTruncatedToMilliseconds = Instant.ofEpochMilli( instant.toEpochMilli() ); String fodderForCassandra = instantTruncatedToMilliseconds.toString(); // Example: 2015-08-18T06:36:40.321Z 

或者根据这个Cassandra Java驱动程序doc ,你可以传递一个java.util.Date实例(不要和java.sqlDate混淆)。 所以你可以在上面的代码中创build一个来自instantTruncatedToMilliseconds

 java.util.Date dateForCassandra = java.util.Date.from( instantTruncatedToMilliseconds ); 

如果经常这样做,你可以做一个单线。

 java.util.Date dateForCassandra = java.util.Date.from( zdt.toInstant() ); 

但是创build一个小实用方法会更好。

 static public java.util.Date toJavaUtilDateFromZonedDateTime ( ZonedDateTime zdt ) { Instant instant = zdt.toInstant(); // Data-loss, going from nanosecond resolution to milliseconds. java.util.Date utilDate = java.util.Date.from( instant ) ; return utilDate; } 

注意所有这些代码的差异,而不是在问题中。 问题的代码试图将ZonedDateTime实例的时区调整为UTC。 但是这不是必要的。 概念:

ZonedDateTime = Instant + ZoneId

我们只是提取即时部分,它已经在UTC(基本上是UTC,阅读类文档的精确细节)。

以下是将当前系统时间转换为UTC的示例。 它涉及将ZonedDateTime格式化为String,然后使用java.text DateFormat将String对象parsing为date对象。

  ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC); final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss"); final DateFormat FORMATTER_YYYYMMDD_HH_MM_SS = new SimpleDateFormat("yyyyMMdd HH:mm:ss"); String dateStr = zdt.format(DATETIME_FORMATTER); Date utcDate = null; try { utcDate = FORMATTER_YYYYMMDD_HH_MM_SS.parse(dateStr); }catch (ParseException ex){ ex.printStackTrace(); } 

您可以使用Java 8及更高版本中内置的java.time类来完成此操作。

 ZonedDateTime temporal = ... long epochSecond = temporal.getLong(INSTANT_SECONDS); int nanoOfSecond = temporal.get(NANO_OF_SECOND); Date date = new Date(epochSecond * 1000 + nanoOfSecond / 1000000); 

如果您现在只对此感兴趣,那么只需使用:

 Date d = new Date(); 

如果您正在使用Android的ThreeTen backport ,并且无法使用较新的Date.from(Instant instant) (需要最less的API 26),则可以使用:

 ZonedDateTime zdt = ZonedDateTime.now(); Date date = new Date(zdt.toInstant().toEpochMilli());