在java.time.LocalDateTime和java.util.Date之间进行转换

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

为此,使用旧类java.util.Date可能有数百万行代码。 因此,在连接新旧代码时,需要在两者之间进行转换。 由于似乎没有直接的办法来完成这个,怎么办呢?

简短的回答:

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

说明:(基于关于LocalDate 这个问题 )

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

JSR-310 java.util.Date的等价类是Instant ,所以有方便的方法来转换:

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

java.util.Date实例没有时区的概念。 如果您在java.util.Date上调用toString() ,这可能看起来很奇怪,因为toString是相对于时区的。 然而,这个方法实际上使用Java的默认时区来提供string。 时区不是java.util.Date实际状态的一部分。

Instant也不包含任何有关时区的信息。 因此,要从Instant转换到本地date时间,有必要指定一个时区。 这可能是默认区域ZoneId.systemDefault() – 或者它可能是应用程序控制的时区,例如用户首选项中的时区。 LocalDateTime有一个方便的工厂方法,可以同时使用即时和时区:

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

相反, LocalDateTime的时区是通过调用atZone(ZoneId)方法来指定的。 ZonedDateTime然后可以直接转换为Instant

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

请注意,从LocalDateTimeZonedDateTime的转换有可能引入意外的行为。 这是因为夏令时并不是每个本地date时间都存在。 在秋季/秋季,当地时间线出现两次相同的本地date – 时间重叠。 spring,一个小时就消失了。 请参阅atZone(ZoneId)的Javadoc atZone(ZoneId)以获取有关转换将执行的更多定义。

总结,如果将一个java.util.Date往返到一个LocalDateTime并返回到一个java.util.Date ,则由于夏令时可能会以不同的瞬间结束。

附加信息:还有一个不同之处,会影响很久的date。 java.util.Date使用一个1582年10月15日的日历,并使用Julian日历而不是公历日历。 相比之下, java.time.*使用ISO日历系统(相当于格里高利)。 在大多数使用情况下,ISO日历系统是您想要的,但在比较1582年之前的date时可能会看到奇怪的效果。

这是我想出来的(就像所有的date时间的谜题,它可能会基于一些奇怪的时区 – 闰日 – 日光调整D)

往返DateDate << – >> LocalDateTime

鉴于: Date date = [some date]

(1) LocalDateTime << Instant << Date

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

(2) Date << Instant << LocalDateTime

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

例:

鉴于:

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

(1) LocalDateTime << Instant << Date

Date创buildInstant

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

Instant创buildDate (不需要,但为了说明):

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

Instant创buildLocalDateTime

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

(2) Date << Instant << LocalDateTime

LocalDateTime创buildInstant

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

Instant创buildDate

 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 

如果你确定你需要一个默认的时区,更方便的方法是:

 Date d = java.sql.Timestamp.valueOf( myLocalDateTime ); 

从新的API LocalDateTime转换到java.util.date时,下面的代码似乎工作:

 Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant()); 

逆向转换可以(希望)以类似的方式实现…

希望它有帮助…

一切都在这里: http : //blog.progs.be/542/date-to-java-time

“往返”的答案并不确切:当你这样做的时候

 LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC); 

如果您的系统时区不是UTC / GMT,则更改时间!

我不确定这是最简单还是最好的方法,或者是否有任何缺陷,但是它是有效的:

 static public LocalDateTime toLdt(Date date) { GregorianCalendar cal = new GregorianCalendar(); cal.setTime(date); ZonedDateTime zdt = cal.toZonedDateTime(); return zdt.toLocalDateTime(); } static public Date fromLdt(LocalDateTime ldt) { ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault()); GregorianCalendar cal = GregorianCalendar.from(zdt); return cal.getTime(); }