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

时间:2013-10-17 15:40:54

标签: java datetime java-8 java-time

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

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

9 个答案:

答案 0 :(得分:653)

简短回答:

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

说明: (基于this question关于LocalDate

尽管有名称,java.util.Date代表时间线上的瞬间,而不是"日期"。存储在对象中的实际数据是自1970-01-01T00:00Z(格林威治标准时间1970 / UTC开始时午夜)以来的long毫秒计数。

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

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

java.util.Date实例没有时区概念。如果您在toString()上致电java.util.Date,这可能会很奇怪,因为toString与时区相关。但是,该方法实际上使用Java的默认时区来提供字符串。时区不是java.util.Date的实际状态的一部分。

Instant也不包含有关时区的任何信息。因此,要从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());

请注意,从LocalDateTimeZonedDateTime的转换可能会引发意外行为。这是因为夏令时不会存在每个本地日期时间。在秋季/秋季,当地时间线存在重叠,其中相同的本地日期时间出现两次。在春天,有一个缺口,一小时消失。有关转换的定义的更多信息,请参阅atZone(ZoneId)的Javadoc。

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

其他信息:还有另一个区别会影响很久的日期。 java.util.Date使用的日历在1582年10月15日更改,日期之前使用Julian日历而不是Gregorian日历。相比之下,java.time.*始终使用ISO日历系统(相当于格里高利)。在大多数用例中,ISO日历系统是您想要的,但在比较1582年之前的日期时您可能会看到奇怪的效果。

答案 1 :(得分:124)

这就是我想出的结果(和所有日期时间难题一样,它可能会因为一些奇怪的时区 - 白昼 - 日光调整而被反驳: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

Instant创建Date

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

Date创建Instant(不是必需的,只是为了说明):

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

LocalDateTime

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

(2)Date<< Instant<< LocalDateTime

Instant创建LocalDateTime

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

Date创建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

答案 2 :(得分:19)

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

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

答案 3 :(得分:7)

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

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

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

希望它有所帮助...

答案 4 :(得分: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();
}

答案 5 :(得分:3)

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

回答"往返"不确切:当你做的时候

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

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

答案 6 :(得分:2)

如果您使用的是Android设备并使用threetenbp,则可以改用DateTimeUtils

例如:

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

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

答案 7 :(得分:1)

LocalDateTime-> Date最快的方式是:

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

答案 8 :(得分: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