2017-08-14 58 views
2

我试图产生从LocalDate对象(java.time.LocalDate),其中我有以下条件的Date对象(java.util.Date):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这是为什么?

我的主要目标是能够捕获一个Date对象,当前UTC日期和时间归零(StartOfDay)。

+3

主要是因为时区不是不相关的 - 在UTC和CDT中的相同日期时间等于不同的Instants(即从纪元秒)。 –

+1

当前时区的一天的开始时间与UTC的一天的开始时间不同。这就是你所看到的。 –

回答

2

当你这样做:

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

首先,createdDate2.atStartOfDay()返回LocalDateTime,这将等同于2017-08-14在午夜。一个LocalDateTime并不时区感知。

当你调用atZone(ZoneId.systemDefault()),它创建了在系统的默认时区ZoneId.systemDefault())相应日期(2017年8月14日)和时间(午夜)一ZonedDateTime。而在你的情况下,默认的时区不是UTC(它的“CDT”,所以它越来越午夜CDT - 只是做System.out.println(ZoneId.systemDefault())检查您的默认时区是什么)。

为了获得在午夜的日期UTC,可以更换默认区域(ZoneId.systemDefault())与UTC(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


只是一个快速注:像CDT或短的时区的名称都不是真正的时区。
API使用IANA timezones names(始终格式为Region/City,如America/ChicagoEurope/Berlin)。 避免使用3字母缩写(如CDT或),因为它们是ambiguous and not standard

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