如何将UTC中已经存在的日期对象转换为Java中UTC本身的OffsetDateTime
对象?这种逻辑应该写在时区可以完全不同的微服务上。我想.now()
和其他东西都排除在外了。另外,我也不想在任何地方将时区作为参数传递。
示例代码:
public OffsetDateTime convertFrom(Date source) {
LOGGER.info("source: " + source.toString());
LOGGER.info("instant: " + source.toInstant().toString());
LOGGER.info("response: " + source.toInstant().atOffset(ZoneOffset.UTC).toString());
return source.toInstant().atOffset(ZoneOffset.UTC);
}
我得到的输出是:
来源:2018-07-11 15:45:13.0
即时:2018-07-11T19:45:13Z
回复:2018-07-11T19:45:13Z
我希望我的输出返回为 2018-07-11 15:45:13Z 输入 2018-07-11 15:45:13.0 < / em>
答案 0 :(得分:2)
一个java.util.Date
和一个Instant
都表示 UTC中的时刻。其他时区和偏移量无关。
Instant instant = myJavaUtilDate.toInstant()
如何用Java将UTC中已经存在的日期对象转换为UTC本身中的OffsetDateTime对象?
您不需要OffsetDateTime
。如上所示,使用Instant
。
ZonedDateTime
,而不是OffsetDateTime
您不需要OffsetDateTime
。与UTC的偏移量只是数小时和数分钟。仅此而已。相反,时区是过去,现在和将来更改特定区域的人们使用的偏移量的历史。因此,时区,如果已知,总是比单纯的偏移更可取。因此,请尽可能使用ZonedDateTime
而不是OffsetDateTime
。
仅在给定与UTC的偏移量(例如OffsetDateTime
)时使用+02:00
,而没有特定时区的上下文(例如Europe/Paris
)。
Date
转换为Instant
如果给定java.util.Date
,则是现代班级的音乐会(Instant
),它将取代那麻烦的旧班级。两者都表示UTC中的某个时刻,作为1970年UTC中第一时刻的相同纪元参考的计数。现代类解析为纳秒而不是毫秒。要进行转换,请调用添加到旧类中的新方法。
Instant instant = myJavaUtilDate.toInstant() ;
请记住,java.util.Date
和Instant
始终都是 ,代表UTC时刻。
以UTC捕获当前时刻。
Instant instant = Instant.now() ;
我猜想排除了now()和其他东西。
否,您始终可以随时通过在任何计算机上调用Instant.now()
来捕获当前时刻。 JVM的当前默认时区无关紧要,因为Instant
在UTC中始终是 。
从UTC调整到另一个时区。 同一时刻,时间轴上的相同点,不同的壁钟时间。 <-这是本次讨论中最重要的概念!
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone() ;
作为一种捷径,您可以在捕获当前时刻时跳过“即时”。
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
通过提取Instant
对象来移回UTC。
Instant instant = zdt.toInstant() ;
通常最好将大部分工作都放在UTC中。在存储,记录,调试或交换时间时,请使用UTC。在以程序员或系统管理员的身份工作时,忘记自己的时区;学习在UTC中思考。在您的办公室中第二次单击以设置为UTC。
避免始终在时区之间切换。坚持使用UTC。仅在向用户展示或业务逻辑需求时才调整为时区。
答案 1 :(得分:0)
它已经按预期工作,问题在于Date.toString
正在“有帮助”地将内部时间戳转换为您的本地时区。使用Date.toGMTString
将为每个值产生完全相同的时间戳。
如果生成的时间戳错误,则问题在于创建Date
实例。使用new Date(2018, 7, 11, 15, 45, 11)
之类的构造函数会导致该日期是针对系统时区(而不是UTC)计算的。要为UTC创建它,有Date.UTC
,但是自Java 1.1以来,所有这些API都已被弃用,因为它们是如此混乱。
答案 2 :(得分:0)
这就是您要的吗
ZonedDateTime zonedDateTime = ZonedDateTime
.of(LocalDateTime.of(2018, 7, 11, 15, 45, 13), ZoneId.of("UTC"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss'Z'", Locale.US);
System.out.println(zonedDateTime.format(formatter));
如果需要将其格式化为给定的格式,则需要使用DateTimeFormatter
。
答案 3 :(得分:0)
public static OffsetDateTime convertFrom(Date source) {
if (source instanceof Timestamp) {
return ((Timestamp) source).toLocalDateTime()
.atOffset(ZoneOffset.UTC);
}
return source.toInstant().atOffset(ZoneOffset.UTC);
}
传递给您的方法的对象是java.sql.Timestamp
,而不是Date
。我们可以从打印方式中看到这一事实:2018-07-11 15:45:13.0
是Timestamp.toString()
的返回值。 Timestamp
类是Date
的子类,但这并不意味着我们也不能将其作为Date
处理。该文档警告我们:
由于
Timestamp
类与 上面提到的java.util.Date
类,建议该代码 不能将Timestamp
的值一般视为java.util.Date
。Timestamp
和之间的继承关系java.util.Date
实际上表示实现继承,而不是 类型继承。
在上面的实现中,我假设您无法减轻获得Timestamp
参数的可能性,因此,我将尽我所能来处理这种可能性。但是,代码仍然很脆弱,因为有时Timestamp
表示一个时间点(我应该说这是时间点),而其他时候则表示日期和时间。如果Timestamp
中没有时区,则两者是不相同的。我们了解到,您的示例Timestamp
表示日期和时间为2018-07-11 15:45:13.0,并且您希望将此时间解释为UTC。我的代码可以做到这一点(另一方面,您问题中的代码可以正确处理Timestamp
表示时间点的情况)。另外,即使我的代码中未传递任何时区,其行为仍取决于JVM的时区设置。
当我将Timestamp
的{{1}}传递到上面的方法时,它返回2018-07-11 15:45:13.0
的{{1}}。
不幸的是,OffsetDateTime
的双重性质令人困惑,唯一的解决方法是,如果您可以完全避免该类的话。 2018-07-11T15:45:13Z
类的设计也很差,并且两者都已过时,被现代Java日期和时间API java.time取代。如果您无法避免代码中的旧类,那么我当然理解您想要转换为现代Timestamp
的愿望。另一方面,如果我正确地理解日期和时间是通过JSON传递的,那么您可能无需任何旧的日期和时间类就可以解析它,这将是解决您的问题的好方法。在所有情况下,如果您的真正目标是以时区中立的方式表示时间点,那么我同意Basil Bourque在UTC中更喜欢Date
而不是OffsetDateTime
。