您可以在下面的示例代码中看到显示的日期与实时(以毫秒为单位)有很大不同。问题是 Sun Oct 30 02:00:00 CET 2016 存在于 CET 和 CEST 时区。切换 CEST => CET 时,您将返回一小时(产生小时重叠)。对于Calendar 对象,这非常棘手,因为您要表达所选时区的时间变化。当您想在这个非常具体的时间重置分钟时,Calendar 必须发现您在哪个时区表示更改。
我不是 100% Calendar 是如何处理这个问题的,但在第一个例子中 CET,你特别建议你想使用 CET。因此,当发生重叠时Calendar 可以选择您的建议(CET)。当您使用GMT 来表达它时,Calendar 必须选择CET 或CEST 的时区之一并选择CEST。
public static void main(String[] args) {
Date date = new Timestamp(1477780200000L);
System.out.println(date); // 2016-10-30 00:30:00.0
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("CET"));
calendar.setTime(date);
print(1, calendar); // 1: Sun Oct 30 00:30:00 CEST 2016 | 1477780200000
calendar.add(Calendar.HOUR_OF_DAY, 2);
print(2, calendar); // 2: Sun Oct 30 02:30:00 CEST 2016 | 1477787400000
calendar.set(Calendar.MINUTE, 0); // minutes expressed in CET
print(3, calendar); // 3: Sun Oct 30 02:00:00 CET 2016 | 1477789200000
System.out.println("--");
calendar = Calendar.getInstance(TimeZone.getTimeZone("CET"));
calendar.setTime(date);
print(4, calendar); // 4: Sun Oct 30 00:30:00 CEST 2016 | 1477780200000
calendar.add(Calendar.HOUR_OF_DAY, 2);
print(5, calendar); // 5: Sun Oct 30 02:30:00 CEST 2016 | 1477787400000
calendar.set(Calendar.MINUTE, 0); // minutes expressed in CET
print(6, calendar); // 6: Sun Oct 30 02:00:00 CET 2016 | 1477789200000
System.out.println("--");
calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+1"));
calendar.setTime(date);
print(4, calendar); // 4: Sun Oct 30 00:30:00 CEST 2016 | 1477780200000
calendar.add(Calendar.HOUR_OF_DAY, 2);
print(5, calendar); // 5: Sun Oct 30 02:30:00 CEST 2016 | 1477787400000
calendar.set(Calendar.MINUTE, 0); // minutes expressed in GMT
print(6, calendar); // 6: Sun Oct 30 02:00:00 CEST 2016 | 1477785600000
}
private static void print(int prefix, Calendar calendar) {
System.out.println(prefix + ": " + calendar.getTime() + " | " + calendar.getTimeInMillis());
}
更新
更有趣的是Calendar方法getTimeInMillis:
public long getTimeInMillis() {
if (!isTimeSet) {
updateTime();
}
return time;
}
如您所见,时间在您获取时已更新!每次使用set 方法(如calendar.set(Calendar.MINUTE, 0))时,都会有一个标志isTimeSet 设置为false。这意味着您的时间在正确的时区/纪元等方面变得无效。这个方法只是将给定的日历字段设置为给定的值,就是这样。此外,如果您的设置有效,此方法不会进行任何额外的检查。另一方面,add 方法尊重日历规则并优雅地移动您的日期。
总结一下。您将分钟设置为 0,这会强制日历重新计算日期。你是对的,set 是有问题的。