2015-03-19 44 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