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

在java.time.LocalDateTime和java.util.Date之间转换,java,datetime,java-8,java-time,Java,Datetime,Java 8,Java Time,Java8有一个全新的日期和时间API。此API中最有用的类之一是LocalDateTime,用于保存具有时间值的时区独立日期 为此,可能有数百万行代码使用遗留类java.util.Date。因此,在连接新旧代码时,需要在两者之间进行转换。由于似乎没有直接的方法来实现这一点,如何才能做到呢?我不确定这是最简单还是最好的方法,或者是否存在任何陷阱,但它是有效的: static public LocalDateTime toLdt(Date date) { GregorianCalendar

Java8有一个全新的日期和时间API。此API中最有用的类之一是
LocalDateTime
,用于保存具有时间值的时区独立日期


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

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

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();
}

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

往返:
Date
LocalDateTime
给定:
Date-Date=[某个日期]

(1)
LocalDateTime
一切都在这里:

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

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

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

从新API LocalDateTime转换为java.util.date时,以下操作似乎有效:

Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant());
反向转换可以(希望)以类似的方式实现

希望它能帮助…

简短回答:

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
说明: (基于大约
LocalDate

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

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的默认时区动态提供字符串。时区不是
java.util.Date
的实际状态的一部分

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

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
反过来,通过调用
atZone(ZoneId)
方法指定时区。然后可以将
ZonedDateTime
直接转换为
即时

LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());
请注意,从
LocalDateTime
ZonedDateTime
的转换可能会引入意外行为。这是因为并非每个本地日期时间都存在夏令时。秋季/秋季,当地时间线重叠,相同的当地日期时间出现两次。在春天,有一个间隙,一个小时消失了。有关转换的定义,请参阅的Javadoc

总之,如果您将
java.util.Date
往返到
LocalDateTime
并返回到
java.util.Date
,则由于夏令时,您可能会得到不同的时刻


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

如果您确定需要默认时区,则更方便:

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

如果您使用的是android,您可以使用
DateTimeUtils

例:


您不能使用
Date.from
,因为它仅在api 26+

上受支持
LocalDateTime
->
Date
的最快方法是:


Date.from(ldt.toInstant(ZoneOffset.UTC))
我认为下面的方法可以解决转换问题,而不考虑时区。 如果有任何缺陷,请评论

    LocalDateTime datetime //input
    public static final DateTimeFormatter yyyyMMddHHmmss_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String formatDateTime = datetime.format(yyyyMMddHHmmss_DATE_FORMAT);
    Date outputDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(formatDateTime); //output

LocalDateTime
Date
肯定有一个陷阱。在夏令时转换时,
LocalDateTime
可能不存在,或出现两次。你需要弄清楚在每种情况下你希望发生什么。顺便说一句,
gregoriacalendar
属于旧的笨拙API,而新的
java.time
API的目标是replace@scottb你是向我还是向提出这个问题的人说的?至于我的想法,如果能在jdk 8 API中明确说明转换,那就太好了——他们至少可以做到这一点。在任何情况下,都有许多库将被重新考虑以包含新的Java-8功能,并且知道如何做到这一点很重要。@scottb为什么第三方的情况会不常见?这太普通了。一个例子:JDBC4及以下版本(希望不是5)。作为一般的JSR-310规则,不需要使用epoch-millis在类型之间进行转换。使用对象存在更好的替代方案,请参见下面我的完整答案。上面的答案也只有在使用UTC这样的区域偏移量时才完全有效-答案的某些部分对于美国/纽约这样的完整时区不起作用,而不是
Instant.ofEpochMilli(date.getTime())
do
date.toInstant()
@goat
toInstant()
看起来不错,但对于
java.sql.date
,啊!因此,使用
Instant.ofE最终变得更容易了
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
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant());
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());
Date d = java.sql.Timestamp.valueOf( myLocalDateTime );
Date date = DateTimeUtils.toDate(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    LocalDateTime datetime //input
    public static final DateTimeFormatter yyyyMMddHHmmss_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String formatDateTime = datetime.format(yyyyMMddHHmmss_DATE_FORMAT);
    Date outputDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(formatDateTime); //output