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


77

我得到以下异常而试图转换java.util.Datejava.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时间回退吗?

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

Answers:


107

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

因此,假设您要使用ZonedDateTime默认时区,则您的代码应为

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

哎呀。谢谢。立即修复。
JB Nizet 2014年

如果我要将其转换为相同的时区怎么办?我相信日期总是UTC,所以我可以做ZoneId.UTC吗?
Didier A.

6
日期完全没有时区。从一个精确的时刻(1970-01-01T00:00 UTC)以来,已经过去了许多毫码。没有“相同”时区。如果希望ZonedDateTime在UTC时区中,则必须传递ZoneOffset.UTC。
JB Nizet 2015年

2
@DidierA。ADate与相似Instant,都是UNIX时间戳。另外,通常的做法是说UNIX时间戳是UTC时区。
kevinarpe

38

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

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

然后,toLocalDate如果需要LocalDate,则可以调用该方法。另请参见:将java.util.Date转换为java.time.LocalDate


上面的解决方案对我也很有效,并且转换为LocalDate非常有用。从设计的角度来看,只要提供了java.time.Instant,ZonedDateTime.from()的行为就应该符合预期。在这种情况下,它不是预期的。这是某种不一致吗?
Ironluca 2014年

3
ZonedDateTime.from()需要一个ZoneId,但是Instant没有一个。因此,ZonedDateTime.from(instant)引发异常。
JodaStephen 2014年

7

通过assylias答案按JB Nizet答案都是正确的:

  1. 调用添加到旧类中的新转换方法, java.util.Date::toInstant
  2. 呼叫Instant::atZone,传递ZoneId,导致ZonedDateTime

在此处输入图片说明

但是您的代码示例针对的是四分之一。为此,请继续阅读。

宿舍

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

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完全淘汰使用方式,请这样做。这是一个可怕的职业,还有其兄弟姐妹CalendarDate当您与尚未更新为java.time的旧代码连接时,仅在必须使用的地方使用。


关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代麻烦的老传统日期时间类,如java.util.DateCalendar,和SimpleDateFormat

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

现在处于维护模式Joda-Time项目建议迁移到java.time类。

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

在哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time。该项目为将来可能在java.time中添加内容打下了基础。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多


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)

不,没有的转换Date::toInstant。根据定义,ajava.util.Date和ajava.time.Instant都在UTC中始终在UTC中。Date代表自1970-01-01T00:00:00Z的纪元以来的毫秒数,同时Instant也代表自相同纪元以来的计数,但分辨率更高。
罗勒·布尔克

LocalDateTime在这里使用的类是完全错误的。该类故意缺少时区或从UTC偏移的任何概念。因此,它无法表示时刻,如其类JavaDoc中所述。转换为aLocalDateTime会丢弃无用的有价值的信息。这个答案是误导和不正确的。请参阅assylias的正确答案。所有您需要获得的ZonedDateTimeDate为:myJavaUtilDate.toInstant().atZone( desiredZoneIdGoesHere )
罗勒·布尔克

罗勒(Basil),我100%同意您的期望,但是可悲的是,这不是我们目睹Java 10在PST JVM中以UTC日期运行的方式。我们在这里仅将LocalDateTime用作中间变量,以免在标记TZ之前弄乱了UTC时间。
TheArchitect

java.sql.Timestamp现在开始,没有理由再使用了,现在已由java.sql.OffsetDateTime-取代了-从JDBC 4.2起,我们可以直接与数据库交换某些java.time类型。
罗勒·布尔克

我建议不要发布此答案,而是发布自己的问题(描述示例)以及示例代码。我们应该能够为您解决问题。
罗勒·布尔克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.