LocalDate不一致

时间:2017-08-14 18:09:39

标签: java date time java-time localdate

我正在尝试从Date对象(java.util.Date)生成LocalDate对象(java.time.LocalDate),其中我有以下条件:

  • 允许从Date对象
  • 中减去特定天数的参数
  • 拥有日期&时间是当前UTC的日期和时间
  • 在一天开始时有时间,00:00:00
  • 时区标记(即CDT或UTC)无关紧要,因为我从String
  • 删除了该标记

为了满足这个标准,我创建了一个测试程序,但是当我修改LocalDate的某个属性时,我得到了有趣的结果。请参阅以下代码:

  public static void main (String args[]) {
    Long processingDaysInPast = 0L;
    LocalDate createdDate1 = LocalDate.now(Clock.systemUTC()).minusDays(processingDaysInPast);
    LocalDate createdDate2 = LocalDate.now(Clock.systemUTC()).minusDays(processingDaysInPast);
    System.out.println(createdDate1);
    System.out.println(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC));
    System.out.println(Date.from(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC)));
    System.out.println((createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
    System.out.println(Date.from(createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
}

输出:

 2017-08-14
 2017-08-14T00:00:00Z
 Sun Aug 13 19:00:00 CDT 2017
 2017-08-14
 2017-08-14T05:00:00Z
 Mon Aug 14 00:00:00 CDT 2017

当我添加值Date.from(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC))时,我会得到日期的预期输出,并带有00:00:00时间字段。但是,如果我不添加此参数,例如:Date.from(createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant())我会在19:00:00前一天得到结果,为什么会这样?

我的主要目标是能够使用当前的UTC日期捕获Date对象,并将时间清零(StartOfDay)。

1 个答案:

答案 0 :(得分:2)

当你这样做时:

createdDate2.atStartOfDay().atZone(ZoneId.systemDefault())

首先,createdDate2.atStartOfDay()返回LocalDateTime,在午夜时相当于2017-08-14LocalDateTime不支持时区。

当您致电atZone(ZoneId.systemDefault())时,会在系统的默认时区中创建一个ZonedDateTime,其中包含相应的日期(2017-08-14)和时间(午夜)ZoneId.systemDefault())。在您的情况下,默认时区不是UTC(它" CDT",所以它在CDT午夜到来 - 只需System.out.println(ZoneId.systemDefault())来检查您的默认时区是)。

要在 UTC 中获取午夜日期,您可以使用UTC(ZoneId.systemDefault())替换默认区域(ZoneOffset.UTC):

Date.from(createdDate2.atStartOfDay().atZone(ZoneOffset.UTC).toInstant())

或(较短的版本):

Date.from(createdDate2.atStartOfDay(ZoneOffset.UTC).toInstant())

当然,您也可以采用与createdDate1相同的方式:

Date.from(createdDate2.atStartOfDay().toInstant(ZoneOffset.UTC))

他们都是等效的,并且会在 UTC 的午夜产生。

快速说明:CDTPST这样的短时区名称不是真正的时区。
API使用IANA timezones names(始终采用Region/City格式,如America/ChicagoEurope/Berlin)。 避免使用3个字母的缩写(例如CDTPST),因为它们是ambiguous and not standard

lots of different timezones可以使用CDT作为缩写。发生这种情况是因为时区是区域在历史记录中具有,拥有和将具有的所有不同偏移的集合。仅仅因为许多地方今天使用CDT,并不意味着它们在过去的同一时期都被使用过,也不会被所有人在未来使用。由于历史不同,会为每个区域创建一个时区。