561

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

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

4

9 回答 9

822

简短的回答:

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

解释:(基于this question about LocalDate

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

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

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

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

AnInstant也不包含有关时区的任何信息。因此,要从一个日期时间转换Instant为本地日期时间,必须指定一个时区。这可能是默认时区 - 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());

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

总结,如果你往返 ajava.util.Date到 aLocalDateTime并返回到 a java.util.Date,由于夏令时,你最终可能会得到不同的瞬间。

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

于 2014-05-27T09:36:14.943 回答
151

这是我想出的(和所有日期时间难题一样,它可能会根据一些奇怪的时区-闰年-日光调整而被反驳: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) 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:

创建InstantDate

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

创建DateInstant(不是必需的,但为了说明):

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

创建LocalDateTimeInstant

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

(2) Date<< Instant<<LocalDateTime

创建InstantLocalDateTime

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

创建DateInstant

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
于 2013-11-01T12:31:19.260 回答
26

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

Date d = java.sql.Timestamp.valueOf( myLocalDateTime );
于 2015-05-08T21:22:38.940 回答
12

LocalDateTime->最快的方法Date是:

Date.from(ldt.toInstant(ZoneOffset.UTC))

于 2019-04-12T14:56:05.060 回答
8

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

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

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

希望能帮助到你...

于 2014-05-27T08:06:10.617 回答
6

如果您在 android 上使用threetenbp,则可以DateTimeUtils改用。

前任:

Date date = DateTimeUtils.toDate(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

你不能使用Date.from,因为它只支持 api 26+

于 2018-09-06T04:37:59.923 回答
5

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

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

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

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

于 2014-05-07T19:03:16.163 回答
3

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

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();
}
于 2013-10-17T15:40:54.290 回答
0

我认为下面的方法将在不考虑时区的情况下解决转换。如有坑请评论。

    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
于 2020-10-09T07:28:03.950 回答