在 java.time.LocalDateTime 和 java.util.Date 之间转换往返:Date <<->> LocalDateTime (1) << << :LocalDateTimeInstantDate(2)Date << Instant << LocalDateTime 输出为:

2022-08-31 04:15:34

Java 8 有一个全新的日期和时间 API。此 API 中最有用的类之一是 ,用于保存与时区无关的时间日期值。LocalDateTime

可能有数百万行代码使用旧版类来实现此目的。因此,在连接新旧代码时,需要在两者之间进行转换。由于似乎没有直接的方法可以做到这一点,那么如何做到这一点呢?java.util.Date


答案 1

简短的回答:

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());

解释:(基于这个问题关于LocalDate)

尽管它的名字,代表时间线上的瞬间,而不是“日期”。对象中存储的实际数据是自 1970-01-01T00:00Z(1970 年 GMT/UTC 开始时的午夜)以来的毫秒数。java.util.Datelong

与 JSR-310 中的类等效的类是 ,因此有方便的方法可以提供来回转换:java.util.DateInstant

Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);

实例没有时区的概念。如果调用 ,这可能看起来很奇怪,因为 是相对于时区的。但是,该方法实际上动态使用Java的默认时区来提供字符串。时区不是 的实际状态的一部分。java.util.DatetoString()java.util.DatetoStringjava.util.Date

也不包含有关时区的任何信息。因此,要从 a 转换为本地日期时间,必须指定时区。这可能是默认区域 - 也可能是应用程序控制的时区,例如用户首选项中的时区。 具有方便的工厂方法,可以同时采用即时和时区:InstantInstantZoneId.systemDefault()LocalDateTime

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());

相反,通过调用该方法指定时区。然后可以直接转换为 :LocalDateTimeatZone(ZoneId)ZonedDateTimeInstant

LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());

请注意,从 到 的转换可能会引入意外行为。这是因为并非每个本地日期时间都由于夏令时而存在。在秋季/秋季,本地时间线中存在重叠,其中相同的本地日期时间出现两次。在春天,有一个空隙,一个小时消失了。请参阅 atZone(ZoneId) 的 Javadoc,了解更多有关转换将执行的操作的定义。LocalDateTimeZonedDateTime

摘要,如果您将 a 往返到 a 并返回到 a,则由于夏令时,您最终可能会得到不同的时刻。java.util.DateLocalDateTimejava.util.Date

其他信息:还有另一个差异会影响非常旧的日期。 使用在 1582 年 10 月 15 日更改的日历,在此之前的日期使用儒略历而不是公历。相比之下,始终使用 ISO 日历系统(相当于公历)。在大多数用例中,ISO日历系统是您想要的,但是在比较1582年之前的日期时,您可能会看到奇怪的效果。java.util.Datejava.time.*


答案 2

以下是我想出的(像所有日期时间难题一样,它可能会根据一些奇怪的时区 - 闰年 - 日光调整:D)被反驳)

往返:Date <<->> LocalDateTime

鉴于:Date date = [some date]

(1) LocalDateTime << Instant<< Date

    Instant instant = Instant.ofEpochMilli(date.getTime());
    LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);

(2) 日期 << 即时<<本地日期时间

    Instant instant = ldt.toInstant(ZoneOffset.UTC);
    Date date = Date.from(instant);

例:

鉴于:

Date date = new Date();
System.out.println(date + " long: " + date.getTime());

(1) << << :LocalDateTimeInstantDate

创建即时起始日期

Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println("Instant from Date:\n" + instant);

即时创建日期(不是必需的,但用于说明):

date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());

即时创建本地日期时间

LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
System.out.println("LocalDateTime from Instant:\n" + ldt);

(2)Date << Instant << LocalDateTime

LocalDateTime 创建即时

instant = ldt.toInstant(ZoneOffset.UTC);
System.out.println("Instant from LocalDateTime:\n" + instant);

即时创建日期

date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());

输出为:

Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574

Instant from Date:
2013-11-01T14:13:04.574Z

Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574

LocalDateTime from Instant:
2013-11-01T14:13:04.574

Instant from LocalDateTime:
2013-11-01T14:13:04.574Z

Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574