2017-08-14 60 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,並不意味着它們在過去同時使用,也不意味着將來它會被所有人使用。由於歷史不同,每個地區都會創建一個時區。