Mil*_*hev 83 java java.util.date datetime-conversion java-8 zoneddatetime
我试图在我的数据库中设置服务器不可知日期时间,我相信这样做的最佳做法是设置UTC日期时间.我的数据库服务器是Cassandra,Java的db驱动程序只能理解Date类型.
所以假设在我的代码中我使用新的Java 8 ZonedDateTime来获取UTC now(ZonedDateTime.now(ZoneOffset.UTC)),我如何将这个ZonedDateTime实例转换为"遗留"Date类?
Sli*_*idi 136
您可以将ZonedDateTime转换为瞬间,您可以直接使用Date.
Date.from(java.time.ZonedDateTime.now().toInstant());
Run Code Online (Sandbox Code Playgroud)
Bas*_*que 53
java.util.Date.from( // Transfer the moment in UTC, truncating any microseconds or nanoseconds to milliseconds.
Instant.now() ; // Capture current moment in UTC, with resolution as fine as nanoseconds.
)
Run Code Online (Sandbox Code Playgroud)
虽然上面的代码没有意义.双方java.util.Date并Instant表示UTC片刻,总是在UTC.上面的代码具有相同的效果:
new java.util.Date() // Capture current moment in UTC.
Run Code Online (Sandbox Code Playgroud)
使用没有任何好处ZonedDateTime.如果您已经拥有ZonedDateTime,请通过提取a来调整为UTC Instant.
java.util.Date.from( // Truncates any micros/nanos.
myZonedDateTime.toInstant() // Adjust to UTC. Same moment, same point on the timeline, different wall-clock time.
)
Run Code Online (Sandbox Code Playgroud)
将答案通过ssoltanid正确解决您的具体问题,如何在新的学校java.time对象(转换ZonedDateTime),以一个老派的java.util.Date对象.Instant从ZonedDateTime中提取并传递给java.util.Date.from().
请注意,您将遭受数据丢失,因为自纪元以来Instant追踪纳秒,而追踪自纪元以来的毫秒数.java.util.Date
您的问题和意见提出了其他问题.
您的服务器通常应将其主机操作系统设置为UTC作为最佳做法.在我所知道的Java实现中,JVM将此主机操作系统设置作为其默认时区.
但是你永远不应该依赖JVM的当前默认时区.启动JVM时传递的标志可以设置另一个时区,而不是选择主机设置.更糟糕的是:任何时候任何应用程序的任何线程中的任何代码都可以调用java.util.TimeZone::setDefault在运行时更改该默认值!
Timestamp类型任何体面的数据库和驱动程序都应自动处理调整传递的UTC日期时间以进行存储.我不使用Cassandra,但似乎对日期时间有一些基本的支持.文档说它的Timestamp类型是相同纪元(1970年第一个UTC时刻)的毫秒数.
此外,Cassandra接受ISO 8601标准格式的字符串输入.幸运的是,java.time使用ISO 8601格式作为解析/生成字符串的默认值.在Instant类的toString实现将很好地做.
但首先我们需要将ZonedDateTime的纳秒精度降低到毫秒.一种方法是使用毫秒创建一个新的Instant.幸运的是,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
Run Code Online (Sandbox Code Playgroud)
或者根据这个Cassandra Java驱动程序文档,您可以传递一个java.util.Date实例(不要混淆java.sqlDate).所以你可以instantTruncatedToMilliseconds在上面的代码中创建juDate .
java.util.Date dateForCassandra = java.util.Date.from( instantTruncatedToMilliseconds );
Run Code Online (Sandbox Code Playgroud)
如果经常这样做,你可以做一个单行.
java.util.Date dateForCassandra = java.util.Date.from( zdt.toInstant() );
Run Code Online (Sandbox Code Playgroud)
但是创建一个小实用方法会更简洁.
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;
}
Run Code Online (Sandbox Code Playgroud)
请注意所有这些代码与问题中的区别.问题的代码试图将ZonedDateTime实例的时区调整为UTC.但这不是必要的.概念:
ZonedDateTime = Instant + ZoneId
我们只提取已经是UTC的Instant部分(基本上是UTC,阅读类doc以获得精确的细节).
该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类?
该ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在此比如找到一些有用的类Interval,YearWeek,YearQuarter,和更多.
如果您使用的是适用于 Android的ThreeTen backport并且不能使用较新的Date.from(Instant instant)(至少需要 API 26),您可以使用:
ZonedDateTime zdt = ZonedDateTime.now();
Date date = new Date(zdt.toInstant().toEpochMilli());
Run Code Online (Sandbox Code Playgroud)
或者:
Date date = DateTimeUtils.toDate(zdt.toInstant());
Run Code Online (Sandbox Code Playgroud)
另请阅读Basil Bourque 的回答中的建议
接受的答案对我不起作用。返回的日期始终是本地日期,而不是原始时区的日期。我住在 UTC+2。
//This did not work for me
Date.from(java.time.ZonedDateTime.now().toInstant());
Run Code Online (Sandbox Code Playgroud)
我想出了两种从 ZonedDateTime 获取正确日期的替代方法。
假设您有夏威夷的 ZonedDateTime
LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(ZoneId.of("US/Hawaii"); // UTC-10
Run Code Online (Sandbox Code Playgroud)
或按照最初要求的 UTC
Instant zulu = Instant.now(); // GMT, UTC+0
ZonedDateTime zdt = zulu.atZone(ZoneId.of("UTC"));
Run Code Online (Sandbox Code Playgroud)
替代方案1
我们可以使用java.sql.Timestamp。它很简单,但它也可能会损害你的编程完整性
Date date1 = Timestamp.valueOf(zdt.toLocalDateTime());
Run Code Online (Sandbox Code Playgroud)
替代方案2
我们从毫秒创建日期(之前已在此回答)。请注意,本地 ZoneOffset 是必须的。
ZoneOffset localOffset = ZoneOffset.systemDefault().getRules().getOffset(LocalDateTime.now());
long zonedMillis = 1000L * zdt.toLocalDateTime().toEpochSecond(localOffset) + zdt.toLocalDateTime().getNano() / 1000000L;
Date date2 = new Date(zonedMillis);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
87117 次 |
| 最近记录: |