Art*_*sky 5 java time datetime calendar date
我注意到 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());
}
}
Run Code Online (Sandbox Code Playgroud)
输出是:
Time in millis: -2209086000000
Date: Sat Dec 30 23:00:00 EET 1899
Local DateTime: 1899-12-30T22:39:49
Run Code Online (Sandbox Code Playgroud)
timeInMillis 必须包含从 传递的毫秒数1970-01-01T00:00:00Z。Date 类的实例存储从 传递的毫秒数1970-01-01T00:00:00Z。
Date.toString()方法返回默认时区的本地日期和时间。
因此Date.toString()和LocalDateTime.toString()必须返回相同的日期和时间,但我们看到了差异(超过 20 分钟)。
这是java的错误,还是我在Java中错误地使用了日期和时间?
LocalDateTime是正确的。根据 TZ 数据库,该日期的 GMT 偏移量为1:39:49:
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Helsinki 1:39:49 - LMT 1878 May 31
1:39:49 - HMT 1921 May # Helsinki Mean Time
2:00 Finland EE%sT 1983
2:00 EU EE%sT
Run Code Online (Sandbox Code Playgroud)
历史时区非常复杂,在标准化之前,偏移量是从基于平均太阳正午等设置继承的。回溯到那么远,几乎任何偏移都是可能的,而IANA TZ 数据库是历史数据的主要参考。
从我在数据库中看到的情况来看,2:00:00直到 1921 年 HMT 被 EE(S)T 取代时,这种奇怪的偏移量才得到标准化。
这是芬兰时间变化造成的奇怪现象,参见1921 年芬兰赫尔辛基 (Helsingfors) 的时钟变化:
\n\n\n1921 年 5 月 1 日 - 时区更改 (HMT \xe2\x86\x92 EET)
\n当当地标准时间即将到达时\n1921 年 5 月 1 日星期日 12:00:00 午夜时钟向前拨动0:20:11 小时到\n1921 年 5 月 1 日星期日中午 12:20:11 当地标准时间反而
\n
这 20 分 11 秒似乎就是你所观察到的。
\n正如吉姆·加里森(Jim Garrison)在他的回答中所说,LocalDateTime正确地处理了这一点,而事实Calendar并非如此。
实际上,似乎旧的TimeZone偏移量是错误的,而新的ZoneId偏移量是正确的,如以下测试代码所示:
public static void main(String[] args) {\n compare(1800, 1, 1, 0, 0, 0);\n compare(1899,12,31, 23,59,59);\n compare(1900, 1, 1, 0, 0, 0);\n compare(1900,12,30, 23, 0, 0);\n compare(1921, 4,30, 0, 0, 0);\n compare(1921, 5, 1, 0, 0, 0);\n compare(1921, 5, 2, 0, 0, 0);\n}\nprivate static void compare(int year, int month, int day, int hour, int minute, int second) {\n Calendar calendar = new GregorianCalendar();\n calendar.clear();\n calendar.setTimeZone(TimeZone.getTimeZone("Europe/Helsinki"));\n calendar.set(year, month-1, day, hour, minute, second);\n Date date = calendar.getTime();\n \n ZonedDateTime zdt = ZonedDateTime.of(year, month, day, hour, minute, second, 0, ZoneId.of("Europe/Helsinki"));\n \n SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z XXX");\n sdf.setTimeZone(TimeZone.getTimeZone("Europe/Helsinki"));\n DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss z XXX");\n \n System.out.printf("%04d-%02d-%02d %02d:%02d:%02d %s = %d %s = %d %d%n",\n year, month, day, hour, minute, second,\n sdf.format(date), date.getTime(),\n dtf.format(zdt), zdt.toInstant().toEpochMilli(),\n date.getTime() - zdt.toInstant().toEpochMilli());\n}\nRun Code Online (Sandbox Code Playgroud)\n输出
\npublic static void main(String[] args) {\n compare(1800, 1, 1, 0, 0, 0);\n compare(1899,12,31, 23,59,59);\n compare(1900, 1, 1, 0, 0, 0);\n compare(1900,12,30, 23, 0, 0);\n compare(1921, 4,30, 0, 0, 0);\n compare(1921, 5, 1, 0, 0, 0);\n compare(1921, 5, 2, 0, 0, 0);\n}\nprivate static void compare(int year, int month, int day, int hour, int minute, int second) {\n Calendar calendar = new GregorianCalendar();\n calendar.clear();\n calendar.setTimeZone(TimeZone.getTimeZone("Europe/Helsinki"));\n calendar.set(year, month-1, day, hour, minute, second);\n Date date = calendar.getTime();\n \n ZonedDateTime zdt = ZonedDateTime.of(year, month, day, hour, minute, second, 0, ZoneId.of("Europe/Helsinki"));\n \n SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z XXX");\n sdf.setTimeZone(TimeZone.getTimeZone("Europe/Helsinki"));\n DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss z XXX");\n \n System.out.printf("%04d-%02d-%02d %02d:%02d:%02d %s = %d %s = %d %d%n",\n year, month, day, hour, minute, second,\n sdf.format(date), date.getTime(),\n dtf.format(zdt), zdt.toInstant().toEpochMilli(),\n date.getTime() - zdt.toInstant().toEpochMilli());\n}\nRun Code Online (Sandbox Code Playgroud)\n