2015-03-19 133 views
33

得到一天的開始有這些有什麼區別:的Java 8日期時間:從ZonedDateTime

zonedDateTime.truncatedTo(ChronoUnit.DAYS); 

zonedDateTime.toLocalDate().atStartOfDay(zonedDateTime.getZone()); 

任何理由,更喜歡一個對其他?

感謝

+17

難道他們不能只是把方法'atStartOfDay()'的'ZonedDataTime'類? – Przemek 2016-01-14 08:12:46

回答

32

更新了校正的緣故:

在大多數情況下是相同的,看到冬天切換到夏天的時候,爲巴西下面的例子:

ZonedDateTime zdt = 
    ZonedDateTime.of(2015, 10, 18, 0, 30, 0, 0, 
    ZoneId.of("America/Sao_Paulo")); // switch to summer time 
ZonedDateTime zdt1 = zdt.truncatedTo(ChronoUnit.DAYS); 
ZonedDateTime zdt2 = zdt.toLocalDate().atStartOfDay(zdt.getZone()); 

System.out.println(zdt); // 2015-10-18T01:30-02:00[America/Sao_Paulo] 
System.out.println(zdt1); // 2015-10-18T01:00-02:00[America/Sao_Paulo] 
System.out.println(zdt2); // 2015-10-18T01:00-02:00[America/Sao_Paulo] 

期截斷情況在當地的時間表上。如果你選擇DAYS,那麼你選擇午夜。根據javadoctruncate() - 方法最終轉換回新的ZonedDateTime並將時間向前移動差距的大小(1小時)。

首先將zdt轉換爲LocalDate(切斷時間部分),然後在給定時區中查找其ZonedDateTime-部分對於這種情況實際上是相同的。

但是,對於從夏令時切換回冬令時的情況,有一個例外(非常感謝@奧斯汀誰反例)。問題出在重疊時決定使用哪個偏移量。通常情況下,類ZonedDateTime設計/指定使用以前的偏移,也看到Javadoc此摘錄:

對於重疊,一般的策略是,如果本地日期,時間 落在重疊的中間,那麼之前的偏移量將保留爲 。如果沒有先前的偏移量,或者先前的偏移量爲 無效,則使用較早的偏移量,通常爲「夏季」時間。

如果該類ZonedDateTime將因此走自己的規範,然後這兩個過程將仍然是等價的含義:

zdt.truncatedTo(ChronoUnit.DAYS); 

應相當於

zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withEarlierOffsetAtOverlap(); 

但根據實際行爲@Austin的例子,並在我自己的測試中確認是:

zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withLaterOffsetAtOverlap(); 

看起來像是在類ZonedDateTime中隱含的不一致,說話溫和。如果你問我哪種方法是首選,那麼我寧願提倡第二種方法,儘管它要長得多,而且需要更多擊鍵。但它對於它的功能更加透明有很大的好處。偏好第二種方法的另一個原因是:

它確實獲得了當地時間等於一天的第一個時刻。否則,在使用第一種方法時,您必須編寫:

zdt.truncatedTo(ChronoUnit.DAYS).withEarlierOffsetAtOverlap(); 
+0

這並不總是正確的!看到我的答案爲什麼不。 – Austin 2017-01-13 00:54:15

+0

@奧斯汀你的答案似乎是合理的。我會相應地調查並糾正我的答案。 – 2017-01-13 07:46:28

21

它們略有不同。根據javadocs,truncatedTo()將嘗試在重疊的情況下保留時區,但atStartOfDay()將查找午夜的首次出現。

例如,古巴恢復夏令時凌晨1點,回落到上午12點。如果您從該轉換後的某個時間開始,則atStartOfDay()將返回上午12點的第一次出現,而truncatedTo()將返回第二次出現。

ZonedDateTime zdt = ZonedDateTime.of(2016, 11, 6, 2, 0, 0, 0, ZoneId.of("America/Havana")); 
ZonedDateTime zdt1 = zdt.truncatedTo(ChronoUnit.DAYS); 
ZonedDateTime zdt2 = zdt.toLocalDate().atStartOfDay(zdt.getZone()); 

System.out.println(zdt); // 2016-11-06T02:00-05:00[America/Havana] 
System.out.println(zdt1); // 2016-11-06T00:00-05:00[America/Havana] 
System.out.println(zdt2); // 2016-11-06T00:00-04:00[America/Havana] 
+1

非常感謝您找到了反例。提高了你的意見並更新了我的答案。 – 2017-01-13 10:48:29

0

注意,也這樣做的另一種方式:

zonedDateTime.with(LocalTime.MIN); 

產生相同的結果truncatedTo

+0

這不是一個真正的答案。 – shmosel 2017-10-23 05:41:32