Java8 java.util.Date转换为java.time.ZonedDateTime

时间:2014-08-19 05:31:52

标签: java date datetime java-8 java-time

我在尝试将java.util.Date转换为java.time.LocalDate时遇到以下异常。

java.time.DateTimeException: Unable to obtain ZonedDateTime from TemporalAccessor: 2014-08-19T05:28:16.768Z of type java.time.Instant

代码如下:

public static Date getNearestQuarterStartDate(Date calculateFromDate){

    int[] quaterStartMonths={1,4,7,10};     
    Date startDate=null;

    ZonedDateTime d=ZonedDateTime.from(calculateFromDate.toInstant());
    int frmDateMonth=d.getMonth().getValue();

我使用ZonedDateTime课程的方式有问题吗?

根据文档,这应该将java.util.Date对象转换为ZonedDateTime。上面的日期格式是标准日期?

我是否必须回到Joda时间?

如果有人可以提供一些建议,那就太棒了。

4 个答案:

答案 0 :(得分:81)

要将Instant转换为ZonedDateTimeZonedDateTime会提供方法ZonedDateTime.ofInstant(Instant, ZoneId)。所以

因此,假设您希望在默认时区中使用ZonedDateTime,则代码应为

ZonedDateTime d = ZonedDateTime.ofInstant(calculateFromDate.toInstant(),
                                          ZoneId.systemDefault());

答案 1 :(得分:32)

要从您可以使用的日期获取ZonedDateTime:

calculateFromDate.toInstant().atZone(ZoneId.systemDefault())

如果您需要LocalDate,则可以调用toLocalDate方法。另见:Convert java.util.Date to java.time.LocalDate

答案 2 :(得分:1)

Answer by assyliasAnswer by JB Nizet都是正确的:

  1. 调用添加到旧类java.util.Date::toInstant中的新转换方法。
  2. 呼叫Instant::atZone,传递一个ZoneId,从而产生一个ZonedDateTime

enter image description here

但是您的代码示例针对的是宿舍。为此,请继续阅读。

四分之一

无需自己动手处理宿舍。使用已经编写和测试的类。

org.threeten.extra.YearQuarter

java.time 类由ThreeTen-Extra项目扩展。在该库中提供的许多方便的类中,您将找到QuarterYearQuarter

首先获取您的ZonedDateTime

ZonedId z = ZoneID.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = myJavaUtilDate.toInstant().atZone( z ) ;

确定该特定日期的年度季度。

YearQuarter yq = YearQuarter.from( zdt ) ;

接下来,我们需要该季度的开始日期。

LocalDate quarterStart = yq.atDay( 1 ) ;

虽然我不一定建议这样做,但是您可以使用一行代码而不是实现一个方法。

LocalDate quarterStart =                    // Represent a date-only, without time-of-day and without time zone.
    YearQuarter                             // Represent a specific quarter using the ThreeTen-Extra class `org.threeten.extra.YearQuarter`. 
    .from(                                  // Given a moment, determine its year-quarter.
        myJavaUtilDate                      // Terrible legacy class `java.util.Date` represents a moment in UTC as a count of milliseconds since the epoch of 1970-01-01T00:00:00Z. Avoid using this class if at all possible.
        .toInstant()                        // New method on old class to convert from legacy to modern. `Instant` represents a moment in UTC as a count of nanoseconds since the epoch of 1970-01-01T00:00:00Z. 
        .atZone(                            // Adjust from UTC to the wall-clock time used by the people of a particular region (a time zone). Same moment, same point on the timeline, different wall-clock time.
            ZoneID.of( "Africa/Tunis" )     // Specify a time zone using proper `Continent/Region` format. Never use 2-4 letter pseudo-zone such as `PST` or `EST` or `IST`. 
        )                                   // Returns a `ZonedDateTime` object.
    )                                       // Returns a `YearQuarter` object.
    .atDay( 1 )                             // Returns a `LocalDate` object, the first day of the quarter. 
;

顺便说一句,如果您可以完全放弃使用java.util.Date,请这样做。它是一个可怕的类,及其兄弟姐妹,例如Calendar。当您与尚未更新为 java.time 的旧代码连接时,仅在必须使用的地方使用Date


关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

答案 3 :(得分:0)

对于在UTC中存储util.Date的Java 10,答案对我不起作用。

Date.toInstant()似乎将EpochMillis转换为服务器的本地时区。

ZDT.ofInstant(instant,zoneId)和Instant.atZone(zoneId)似乎只是在瞬间标记了TZ,但已经搞砸了。

我找不到防止Date.toInstant()与系统时区的UTC时间混淆的方法。

我发现解决此问题的唯一方法是遍历sql.Timestamp类:

new java.sql.Timestamp(date.getTime()).toLocalDateTime()
                                      .atZone(ZoneId.of("UTC"))
                                      .withZoneSameInstant(desiredTZ)