java - 将 Java 日期转换为 OffsetDateTime

标签 java spring java-time date

我有一个 eta 值,它是一个 OffsetDateTime,我有一个 scheduledDate 是一个 Date 类型。如果未设置 eta,我想回退到日期。

日期的示例是 Tue Jul 21 10:32:28 PDT 2020。要转换它,我尝试这样做: OffsetDateTime.ofInstant(dto.getScheduledTime().ToInstant(), ZoneOffset.UTC) 感觉 utc 偏移量是错误的,因为日期中已经包含 PDT,但同时它也不是像“America/Los_Angeles”这样的 timezoneId。

我对如何处理这个问题有点困惑。

最佳答案

tl;dr

OffsetDateTime target, eta;    // Modern java.time class.
java.util.Date scheduledDate;  // Terrible legacy class.


if(Objects.isNull(eta)) {   // If no eta, fall back to scheduledDate.
    target = scheduledDate.toInstant().atOffset( ZoneOffset.UTC ); // Never use legacy class `java.util.Date` -- when encountered, immediately convert to modern `java.time.Instant`. 
} else {  // Else not null.
    target = eta;
}
return target;

最好完全避免 java.util.Date。遇到时,立即转换为现代类Instant,而忘记所有Date对象。

OffsetDateTime target, eta, scheduled;
scheduled = incomingJavaUtilDate.toInstant().atOffset(ZoneOffset.UTC);

target = Objects.isNull(eta) ? scheduledDate : eta;  // Ternary operator. Short way of saying: If eta is null, go with scheduledDate, otherwise go with eta. 
return target;

Date::toString 骗你

首先,了解 java.util.Date 表示 UTC 中的时刻,始终采用 UTC。然而,它的 toString 方法具有动态应用 JVM 当前默认时区的非常令人困惑的反特性的善意。这造成了 Date 有时区的错误印象,而实际上它没有

避免遗留日期时间类

其次,您将非常好的现代 java.time 类 (OffsetDateTime) 与非常糟糕的遗留日期时间类 (Date )。不要这样做。完全避免遗留类。它们因采用 JSR 310 而被淘汰。回到 2014 年。

table of date-time classes in Java, both legacy and modern

使用java.time

如果传递给 java.util.Date 对象,立即转换为 java.time。调用添加到旧类的新转换方法。 Instant 类直接替换 Date,作为 UTC 中的一个时刻,但具有纳秒与毫秒的更精分割辨率。

Instant instant = myJavaUtilDate.toInstant();  // Convert from legacy class to modern class.

您通常应该在 UTC 中跟踪时刻。您可以将其作为 Instant 或将其偏移设置为 ZoneOffset.UTC 常量的 OffsetDateTime 来执行此操作。

OffsetDateTime odt = instant.atOffset(ZoneOffset.UTC);  // Same moment, no change in meaning whatsoever. 

特别是对于 UTC,我们这里的代码中的 instantodt 没有区别。它们都代表 UTC 中的一个时刻。不同之处在于 OffsetDateTime (a) 可以携带替代的 UTC 偏移量值(小时-分钟-秒),并且 (b) 更灵活,例如以非标准格式生成文本ISO 8601 .

了解 offset-from-UTC仅仅是小时数、分钟数和秒数。而已。 time zone相比之下,。时区是特定地区的人们使用的偏移量的过去、现在和 future 变化的历史。例如,使用 America/Los_Angeles 时区的地区的人们每年两次以一种称为 Daylight Saving Time (DST) 的愚蠢做法更改他们的 UTC 偏移量。从 -08:00 到 -07:00 然后再返回。

因此,通常情况下,时区比单纯的偏移更可取。例如,要查看您的日期,我们通过美国西海岸大多数人使用的挂钟时间变成了Instant,应用时区 America/Los_Angeles (ZoneId) 到 Instant 以获取 ZonedDateTime

ZoneId z = ZoneId.of("America/Los_Angeles");
ZonedDateTime zdt = instant.atZone(z);

您可以通过提取 Instant 返回到 UTC。

Instant instant = zdt.toInstant();

然后从那里返回到 java.util.Date(如果必须,否则避免)。

java.util.Date d = java.util.Date.from(instant);

实际上,java.time.Date确实有一个隐藏在深处的时区。缺少任何访问器(获取/设置)方法,它是不可访问的。它的行为与我们在这里的讨论无关。令人困惑?是的。避免可怕的遗留日期时间类的另一个原因。

关于java - 将 Java 日期转换为 OffsetDateTime,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52633045/

相关文章:

java - JsonIgnoreType 只查看字段声明的类型?

java - 如何确保主键值没有间隙,即使在删除之后也是如此?

java - Linux/X Window 系统下的屏幕阅读/鼠标点击?

java - Sprint Boot ProducerTemplate 作为构造函数参数失败

java - 从 java.time.MonthDay 到 java.sql.* 的映射

Java 11 编译器无法识别 main 方法中的静态 BiFunction

java - 接口(interface)类名中的标签 <>

java - Spring/Spring Boot 转换 - 如何在 Converters 上建立链?

由 java.time.Instant 的 MIN/MAX 生成的 java.sql.Timestamp 的行为与由 Long.MIN_VALUE/Long.MAX_VALUE 构造时的行为不同

java - 将 java.util.Date 截断为 LocalDate *没有* toInstant() 因为 java.sql.Date 给出 UnsupportedOperationException