我注意到 java 中日期和时间的奇怪行为。我有以下代码:
public class TestDateTime {
public static void main(String[] args) {
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Helsinki"));
Calendar calendar = GregorianCalendar.getInstance();
assert(calendar.getTimeZone().equals(TimeZone.getDefault()));
//Set 1899-12-30T23:00:00
calendar.set(1899,11,30,23,0,0);
calendar.set(Calendar.MILLISECOND,0);
long timeInMillis = calendar.getTimeInMillis();
java.util.Date calendarDateTime = new java.util.Date(timeInMillis);
LocalDateTime localDateTime = LocalDateTime.ofInstant(ofEpochMilli(timeInMillis), ZoneId.systemDefault());
System.out.println("Time in millis: " + timeInMillis);
System.out.println("Date: " + calendarDateTime.toString());
System.out.println("Local DateTime: " + localDateTime.toString());
}
}
输出是:
Time in millis: -2209086000000
Date: Sat Dec 30 23:00:00 EET 1899
Local DateTime: 1899-12-30T22:39:49
timeInMillis 必须包含从 1970-01-01T00:00:00Z
传递的毫秒数。
Date 类的实例存储从 1970-01-01T00:00:00Z
传递的毫秒数。
Date.toString()
方法返回默认时区的本地日期和时间。
因此 Date.toString()
和 LocalDateTime.toString()
必须返回相同的日期和时间,但我们看到了差异(超过 20 分钟)。
这是 java 的错误,还是我在 Java 中错误地使用了日期和时间?
最佳答案
这是芬兰时间变化造成的怪异现象,参见Clock Changes in Helsinki, Finland (Helsingfors) in 1921 :
May 1, 1921 - Time Zone Change (HMT → EET)
When local standard time was about to reach Sunday, May 1, 1921, 12:00:00 midnight clocks were turned forward 0:20:11 hours to Sunday, May 1, 1921, 12:20:11 am local standard time instead
那 20 分 11 秒似乎就是您所观察到的。
作为Jim Garrison said in his answer , LocalDateTime
正确处理了它,而 Calendar
则没有。
实际上,似乎旧的 TimeZone
得到的偏移量是错误的,而新的 ZoneId
得到的是正确的,如以下测试代码所示:
public static void main(String[] args) {
compare(1800, 1, 1, 0, 0, 0);
compare(1899,12,31, 23,59,59);
compare(1900, 1, 1, 0, 0, 0);
compare(1900,12,30, 23, 0, 0);
compare(1921, 4,30, 0, 0, 0);
compare(1921, 5, 1, 0, 0, 0);
compare(1921, 5, 2, 0, 0, 0);
}
private static void compare(int year, int month, int day, int hour, int minute, int second) {
Calendar calendar = new GregorianCalendar();
calendar.clear();
calendar.setTimeZone(TimeZone.getTimeZone("Europe/Helsinki"));
calendar.set(year, month-1, day, hour, minute, second);
Date date = calendar.getTime();
ZonedDateTime zdt = ZonedDateTime.of(year, month, day, hour, minute, second, 0, ZoneId.of("Europe/Helsinki"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z XXX");
sdf.setTimeZone(TimeZone.getTimeZone("Europe/Helsinki"));
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss z XXX");
System.out.printf("%04d-%02d-%02d %02d:%02d:%02d %s = %d %s = %d %d%n",
year, month, day, hour, minute, second,
sdf.format(date), date.getTime(),
dtf.format(zdt), zdt.toInstant().toEpochMilli(),
date.getTime() - zdt.toInstant().toEpochMilli());
}
输出
1800-01-01 00:00:00 1800-01-01 00:00:00 EET +02:00 = -5364669600000 1800-01-01 00:00:00 EET +01:39 = -5364668389000 -1211000
1899-12-31 23:59:59 1899-12-31 23:59:59 EET +02:00 = -2208996001000 1899-12-31 23:59:59 EET +01:39 = -2208994790000 -1211000
1900-01-01 00:00:00 1900-01-01 00:00:00 EET +02:00 = -2208996000000 1900-01-01 00:00:00 EET +01:39 = -2208994789000 -1211000
1900-12-30 23:00:00 1900-12-30 23:00:00 EET +01:39 = -2177548789000 1900-12-30 23:00:00 EET +01:39 = -2177548789000 0
1921-04-30 00:00:00 1921-04-30 00:00:00 EET +01:39 = -1536025189000 1921-04-30 00:00:00 EET +01:39 = -1536025189000 0
1921-05-01 00:00:00 1921-05-01 00:20:11 EET +02:00 = -1535938789000 1921-05-01 00:20:11 EET +02:00 = -1535938789000 0
1921-05-02 00:00:00 1921-05-02 00:00:00 EET +02:00 = -1535853600000 1921-05-02 00:00:00 EET +02:00 = -1535853600000 0
关于java - 在 Java 中处理日期和时间的不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42865515/