Java 8有一个全新的日期和时间API。此API中最有用的类之一是LocalDateTime
,用于保存与时区无关的日期与时间值。
为此目的,使用遗留类java.util.Date
可能有数百万行代码。因此,当连接新旧代码时,需要在两者之间进行转换。由于似乎没有直接的方法来实现这一点,怎么办呢?
答案 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());
请注意,从LocalDateTime
到ZonedDateTime
的转换可能会引发意外行为。这是因为夏令时不会存在每个本地日期时间。在秋季/秋季,当地时间线存在重叠,其中相同的本地日期时间出现两次。在春天,有一个缺口,一小时消失。有关转换的定义的更多信息,请参阅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());
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);
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