为了更正而更新:
在大多数情况下是一样的,请参阅以下巴西从冬季时间切换到夏季时间的示例:
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,那么您选择午夜。根据javadoc,truncate()-方法最终转换回新的ZonedDateTime,并将时间向前移动间隔的大小(1 小时)。
首先将 zdt 转换为 LocalDate(切断时间部分),然后在给定时区中查找其 ZonedDateTime-part 对于这种情况实际上是相同的。
但是,对于从夏令时切换回冬令时的相反情况,有一个例外(非常感谢@Austin 提供了一个反例)。问题是在重叠期间何时决定使用哪个偏移量。通常ZonedDateTime 类被设计/指定为使用以前的偏移量,另请参见Javadoc 的摘录:
对于 Overlaps,一般的策略是如果本地日期时间
落在重叠的中间,那么前一个偏移量将是
保留。如果没有前一个偏移量,或者前一个偏移量是
无效,则使用较早的偏移量,通常是“夏季”时间。
如果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();