在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());
请注意,从LocalDateTime
到ZonedDateTime
的转换有可能引入意外的行为。 这是因为夏令时并不是每个本地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)
往返Date
: Date
<< – >> 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(); }