Bas*_*que 34 java datetime date java-time
我有一个java.util.Date对象或一个java.util.Calendar对象.如何在java.time框架中将其转换为正确的类型?
我听说我们现在应该使用java.time类型来处理大部分业务逻辑.使用尚未针对java.time更新的旧代码时,我需要能够来回转换.什么类型映射到java.util.Date或java.util.Calendar?
Bas*_*que 100
是的,你肯定应该尽可能使用java.time框架.
旧的日期时间类,包括java.util.Date,java.util.Calendar等等java.text.SimpleTextFormat,已被证明设计不当,令人困惑和麻烦.尽可能避免使用它们.但是当您必须与这些旧类型进行互操作时,您可以在旧的和新的之间进行转换.
继续阅读一些基本的介绍,有些过于简化,以指导您在旧的和新的日期时间类之间来回移动.
该java.time框架由定义JSR 310,由大获成功的启发乔达时库,并通过扩展ThreeTen-EXTRA项目.的功能的大部分被后移植到Java 6和7在ThreeTen-反向移植项目,在为Android进一步适配ThreeTenABP项目.
什么java.time类型匹配java.util.Date?好吧,一个java.util.Date对象基本上代表UTC时间轴上的一个时刻,它是日期和时间的组合.我们可以将它转换为java.time中的几种类型中的任何一种.每个都在下面讨论.请注意,旧的日期时间类中添加了一些新方法以方便转换.
通常,您应该在UTC中执行大部分业务逻辑.在这样的工作中,Instant会经常使用.传递Instant对象,仅应用时区以呈现给用户.如果确实需要应用偏移或时区,请使用下面进一步介绍的类型.
java.util.Date到Instant鉴于这两个Instant和java.util.Date在UTC时间线上的时刻,我们可以很容易地从一个移动java.util.Date到Instant.老班学获得了一种新方法java.util.Date::toInstant.
Instant instant = myUtilDate.toInstant();
Run Code Online (Sandbox Code Playgroud)
你可以走另一个方向,从一个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);
Run Code Online (Sandbox Code Playgroud)
java.util.Calendar到Instant怎么样java.util.Calendar而不是java.util.Date?在Calendar对象内部,日期时间被跟踪为UTC()中1970年第一时刻的历元参考日期时间的毫秒数.所以这个值可以很容易地转换为.1970-01-01T00:00:00.0ZInstant
Instant instant = myUtilCalendar.toInstant() ;
Run Code Online (Sandbox Code Playgroud)
java.util.GregorianCalendar到ZonedDateTime更好的是,如果您的java.util.Calendar对象实际上是一个,java.util.GregorianCalendar您可以轻松地直接进入ZonedDateTime.该方法具有保留嵌入时区信息的优点.
垂头丧气从接口的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`
}
Run Code Online (Sandbox Code Playgroud)
走向另一个方向......
java.util.Calendar myUtilCalendar = java.util.GregorianCalendar.from(zdt); // Produces an instant of `GregorianCalendar` which implements `Calendar` interface.
Run Code Online (Sandbox Code Playgroud)
如上所述,请注意您可能会丢失有关秒数的信息.在纳秒在java.time类型(ZonedDateTime)被截断,以毫秒为单位的.Calendar/ .GregorianCalendar.
OffsetDateTime从Instant我们可以应用一个从UTC的偏移量进入某个地方的挂钟时间.偏移量是UTC(向东)之前或UTC之后(向西)之前的小时数,可能是分钟数和秒数.这个ZoneOffset类代表了这个想法.结果是一个OffsetDateTime对象.
ZoneOffset offset = ZoneOffset.of("-04:00");
OffsetDateTime odt = OffsetDateTime.ofInstant(instant, zoneOffset);
Run Code Online (Sandbox Code Playgroud)
你可以走另一个方向,从一个OffsetDateTime到一个java.util.Date.提取一个Instant然后按照我们在上面的代码中看到的那样继续.如上所述,任何纳秒都会被截断为毫秒(数据丢失).
java.util.Date myUtilDate = java.util.Date.from(odt.toInstant());
Run Code Online (Sandbox Code Playgroud)
ZonedDateTime更好的是,应用一个全时区.时区是偏移加上用于处理诸如夏令时(DST)之类的异常的规则.
应用a ZoneId可以获得一个ZonedDateTime对象.使用适当的时区名称(大陆/地区).不要使用常见的如3-4个字母的缩写EST或IST因为它们既不规范,也不是唯一的.
ZoneId zoneId = ZoneId.of("America/Montreal");
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, zoneId);
Run Code Online (Sandbox Code Playgroud)
你可以走另一个方向,从一个ZonedDateTime到一个java.util.Date.提取一个Instant然后按照我们在上面的代码中看到的那样继续.如上所述,任何纳秒都会被截断为毫秒(数据丢失).
java.util.Date myUtilDate = java.util.Date.from( zdt.toInstant() );
Run Code Online (Sandbox Code Playgroud)
我们进一步看到a ZonedDateTime可以转换为a GregorianCalendar.
LocalDate有时您可能需要一个仅限日期的值,没有时间和没有时区.为此,请使用java.time.LocalDate对象.
有关更多讨论,请参阅此问题,将java.util.Date转换为java.time.LocalDate,尤其是此答案由Joda-Time和java.time发明背后的主要人员撰写.
关键是要经过一个ZonedDateTime(如上面代码中生成的那样).我们需要一个时区来确定日期.世界各地的日期各不相同,东部早些时候开始新的一天.例如,在巴黎的午夜之后是新的一天,而在蒙特利尔仍然是"昨天".因此,虽然a LocalDate不包含时区,但需要时区来确定 a LocalDate.
LocalDate localDate = zdt.toLocalDate();
Run Code Online (Sandbox Code Playgroud)
从另一个方向转换LocalDate到日期时间意味着发明一个时间.您可以选择在您的业务场景中有意义的任何时间.对于大多数人来说,一天的第一时刻是有道理的.您可能很想将第一时刻的硬编码作为时间00:00:00.0.在某些时区,由于夏令时(DST)或其他异常,该时间可能无效作为第一时刻.所以让java.time通过调用来确定正确的时间atStartOfDay.
ZonedDateTime zdt = localDate.atStartOfDay(zoneId);
Run Code Online (Sandbox Code Playgroud)
LocalTime在极少数情况下,您可能只需要一个没有日期且没有时区的时间.这个概念由LocalTime班级代表.如上所述LocalDate,我们需要一个时区来确定LocalTime即使LocalTime对象不包含(不"记住")该时区.因此,我们再次通过ZonedDateTime从Instant上面看到的对象获得.
LocalTime localTime = zdt.toLocalTime();
Run Code Online (Sandbox Code Playgroud)
LocalDateTime与其他两种Local…类型一样,a LocalDateTime没有分配时区和偏移量.因此,您可能很少使用它.它可以让您大致了解日期时间,但不是时间轴上的一个点.如果您指的是某个通用日期和可能应用于时区的某个时间,请使用此选项.
例如,"今年圣诞节开始"将是2016-12-25T00:00:00.0.请注意,在该文本表示中缺少任何偏移或时区LocalDateTime.印度德里的圣诞节比法国巴黎的圣诞节开始得更早,后来仍然在蒙特利尔魁北克加拿大.应用这些区域的每个时区将在时间轴上产生不同的时刻.
LocalDateTime ldt = zdt.toLocalDateTime();
Run Code Online (Sandbox Code Playgroud)