将java.util.Date转换为什么“java.time”types?
我有一个java.util.Date
对象或一个java.util.Calendar
对象。 如何将其转换为java.time框架中的正确types?
我听说现在我们应该用java.timetypes来完成大部分业务逻辑。 当使用旧时间代码尚未更新的时间我需要能够来回转换。 什么types映射到java.util.Date
或java.util.Calendar
?
是的,你绝对应该尽可能使用java.time框架。
避免旧的date时间课程
包括java.util.Date
, java.util.Calendar
和java.text.SimpleTextFormat
等在内的旧date时间类已被certificate是devise不佳,令人困惑和麻烦的 。 避免他们在可能的地方。 但是,当你必须与这些旧的types互操作时,你可以在新旧之间进行转换。
请继续阅读以获得基本介绍,稍微简化一下,以便让您在旧date和新date时间之间来回移动。
java.time
java.time框架由JSR 310定义,受到高度成功的Joda-Time库的启发,并由ThreeTen-Extra项目扩展。 在ThreeTen-Backport项目中,大部分function都被移植到了Java 6和7中,并在ThreeTenABP项目中进一步改进了Android。
什么java.timetypes与java.util.Date
匹配? 那么, java.util.Date
对象基本上代表了UTC时间轴上的一个时刻,它是date和时间的组合。 我们可以把它翻译成java.time中的任何几种types。 每个都在下面讨论。 请注意,一些新的方法已被添加到旧的date时间类,以促进转换。
Instant
java.time中的构build块是一个Instant
, UTC中的时间轴上的一个分辨率为纳秒的时刻。
一般来说,你应该用UTC来完成大部分业务逻辑。 在这样的工作中, Instant
会经常使用。 传递Instant
对象,仅将时区应用于用户呈现。 如果需要应用偏移量或时区,请使用下面进一步介绍的types。
从java.util.Date
到Instant
鉴于Instant
和java.util.Date
都是UTC时间轴上的一个时刻,我们可以很容易地从java.util.Date
移动到Instant
。 旧类已经获得了一个新的方法java.util.Date::toInstant
。
Instant instant = myUtilDate.toInstant();
你可以从另一个方向,从Instant
到java.util.Date
。 但是,您可能会丢失关于小数秒的信息。 Instant
追踪纳秒 ,小数点后最多九位数字,如2016-01-23T12:34:56.123456789Z
。 java.util.Date&.Calendar都被限制为毫秒 ,小数点后最多三位数,如2016-01-23T12:34:56.123Z
。 在这个例子中,从Instant
到Date
意味着截断456789
。
java.util.Date myUtilDate = java.util.Date.from( instant );
从java.util.Calendar
到Instant
怎么样java.util.Calendar
而不是java.util.Date
? 在Calendar
对象的内部,date时间被跟踪为以UTC( 1970-01-01T00:00:00.0Z
)的1970年第一时间的历元引用date时间的毫秒数。 所以这个值可以很容易地转换成Instant
。
Instant instant = myUtilCalendar.toInstant() ;
从java.util.GregorianCalendar
到ZonedDateTime
更妙的是,如果你的java.util.Calendar
对象实际上是一个java.util.GregorianCalendar
你可以直接进入一个ZonedDateTime
。 这种方法有保留embedded的时区信息的好处。
从Calendar
的界面 下降到GregorianCalendar
的具体类 。 然后调用toZonedDateTime
和from
方法来回。
if( myUtilCalendar instanceof GregorianCalendar ) { GregorianCalendar gregCal = (GregorianCalendar) myUtilCalendar; // Downcasting from the interface to the concrete class. ZonedDateTime zdt = gregCal.toZonedDateTime(); // Create `ZonedDateTime` with same time zone info found in the `GregorianCalendar` end if
走向另一个方向
java.util.Calendar myUtilCalendar = java.util.GregorianCalendar.from( zdt ); // Produces an instant of `GregorianCalendar` which implements `Calendar` interface.
如上所述,请注意,您可能会丢失有关秒的小数部分的信息 。 .Calendar
/ .GregorianCalendar
中的java.timetypes( ZonedDateTime
)中的毫微秒会被截断为毫秒 。
OffsetDateTime
从Instant
我们可以应用从UTC的偏移量移动到某个地点的挂钟时间 。 偏移量是UTC (向东)或UTC(西向)之后的小时数,可能是分钟和秒。 ZoneOffset
类表示这个想法。 结果是一个OffsetDateTime
对象。
ZoneOffset offset = ZoneOffset.of( "-04:00" ); OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset );
你可以走另一个方向,从OffsetDateTime
到java.util.Date
。 提取Instant
,然后按照上面的代码进行操作。 如上所述,任何纳秒都会被截断到毫秒 ( 数据丢失 )。
java.util.Date myUtilDate = java.util.Date.from( odt.toInstant() );
ZonedDateTime
更好的是,应用一个全时区 。 时区是偏移加上处理exception情况(如夏令时(DST))的规则 。
应用ZoneId
会为您提供一个ZonedDateTime
对象。 使用适当的时区名称 (大陆/地区)。 切勿使用通常所见的3-4字母缩写(如EST
或IST
因为它们既不标准也不唯一。
ZoneId zoneId = ZoneId.of( "America/Montreal" ); ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
你可以从ZonedDateTime
转到java.util.Date
。 提取Instant
,然后按照上面的代码进行操作。 如上所述,任何纳秒都会被截断到毫秒 ( 数据丢失 )。
java.util.Date myUtilDate = java.util.Date.from( zdt.toInstant() );
而且我们在上面看到, ZonedDateTime
可能会转换为GregorianCalendar
。
LocalDate
有时你可能想要一个只有date的值,没有时间和没有时区。 为此,使用java.time.LocalDate
对象。
请参阅这个问题的更多讨论, 转换java.util.Date到java.time.LocalDate ,特别是这个答案写的主要背后的人Joda-Time和java.time的发明。
关键是要通过一个ZonedDateTime
(如上面的代码生成)。 我们需要一个时区来确定一个date。 date在世界各地不同,在东部早些时候有了新的一天。 例如,巴黎的午夜过后是新的一天,而在蒙特利尔仍然是“昨天”。 因此,当LocalDate
不包含时区时,需要时区来确定 LocalDate
。
LocalDate localDate = zdt.toLocalDate();
从LocalDate
转换到date时间意味着创build一个时间。 您可以select在您的业务场景中有意义的任何时间。 对大多数人来说,一天中的第一个时刻是有意义的。 在00:00:00.0
的时候,你可能会试图在第一时间硬编码。 在某些时区,由于夏令时(DST)或其他exception情况,这段时间可能无法在第一时间有效。 所以让java.time通过调用atStartOfDay来确定正确的时间。
ZonedDateTime zdt = localDate.atStartOfDay( zoneId );
LocalTime
在极less数情况下,您可能只需要一个没有date和时区的时间。 这个概念由LocalTime
类表示。 正如上面用LocalDate
所讨论的,即使LocalTime
对象不包含(不记住)该时区,我们也需要一个时区来确定LocalTime
。 所以,我们再次通过一个从Instant
获得的ZonedDateTime
对象,如上所示。
LocalTime localTime = zdt.toLocalTime();
LocalDateTime
与其他两个Local…
types一样, LocalDateTime
没有时区和偏移量。 因此你可能很less使用这个。 它给你一个date时间的概念,但不是时间轴上的一个点。 如果你的意思是一些普通的date和一些可能适用于某个时区的时间,请使用它。
例如,“今年圣诞节开始”将是2016-12-25T00:00:00.0
。 请注意, LocalDateTime
文本表示中缺less任何偏移量或时区。 德里印度的圣诞节早于巴黎法国,后来在加拿大魁北克省的蒙特利尔。 应用这些区域的每个时区将在时间轴上产生不同的时刻。
LocalDateTime ldt = zdt.toLocalDateTime();