我刚刚发现了JAVA Calendar Class的一个奇怪的行为。 当我将分钟设置为0时,结果因使用的TimeZone而异。
有谁知道为什么?
示例代码
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class CalendarTest {
public static void main(String[] args) {
Date date = new Timestamp(1477780200000L);
System.out.println(date); // 2016-10-30 00:30:00.0
testMethod(date, Calendar.getInstance(TimeZone.getTimeZone("CET"))); // Sun Oct 30 02:00:00 CET 2016
testMethod(date, Calendar.getInstance(TimeZone.getTimeZone("GMT+1"))); // Sun Oct 30 02:00:00 CEST 2016
}
private static void testMethod(Date date, Calendar c) {
c.setTime(date);
c.add(Calendar.HOUR_OF_DAY, 2);
c.set(Calendar.MINUTE, 0);
System.out.println(c.getTime());
}
}
编辑(使我的问题更容易理解):
更改了testMethod
这个改变的方法在BOTH(!)情况下计算 Sun Oct 30 02:30:00 CEST 2016 。
private static void testMethod(Date date, Calendar c) {
c.setTime(date);
c.add(Calendar.HOUR_OF_DAY, 2);
System.out.println(c.getTime());
}
答案 0 :(得分:3)
您可以在下面的示例代码中看到,显示的日期与实时(以毫秒为单位)有很大不同。问题是2016年10月30日02:00:00 CET
存在于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;
}
正如您所知,时间会在您获得时更新!每次使用isTimeSet
方法false
时,都会设置一个set
标记calendar.set(Calendar.MINUTE, 0)
。这意味着您的时间在正确的时区/纪元等方面变为无效。此方法只是将给定的日历字段设置为给定的值,就是这样。此外,如果您的设置有效,此方法不会进行任何其他检查。另一方面,add
方法尊重日历规则并优雅地移动日期。
总结一下。您将分钟设置为0会强制日历重新计算日期。你是对的,set
是有问题的。