如何将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
在运行时更改默认值!
卡桑德拉Timestamp
types
任何体面的数据库和驱动程序都应该自动处理将通过的date时间调整为UTC以进行存储。 我不使用卡桑德拉,但它似乎对date时间有一些基本的支持。 该文档说,其Timestamp
types是从同一纪元(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());