1927年:时间倒流的那一刻
\n\n想象一下:你正在用Java编写一个简单的脚本,用于计算两个日期之间的毫秒差。你取1927年,从一个值中减去另一个值——结果得到的不是3600秒(一小时),而是一个奇怪的数字。你反复检查代码,上网搜索,找到了StackOverflow上那个拥有数千次浏览的传奇问题。然后你明白了:你并不孤单。
\n\n这个Bug是一个真正的历史产物,至今仍让新手感到困惑。在本文中,我们将分析为什么1927年的epoch毫秒时间减法会得出奇怪结果,通过真实的Java代码示例进行展示,最重要的是,给出避免这个陷阱的有效方法。如果你在处理历史数据,或者只是想编写可靠的代码——这些信息对你来说很有用。
\n\n问题本质:1927年12月31日的魔法
\n\n让我们直接看代码。这是一个经典的让人头疼的例子:
\n\nimport java.util.TimeZone;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class StrangeDateDifference {\n public static void main(String[] args) throws Exception {\n TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");\n SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\n sdf.setTimeZone(tz);\n\n Date date1 = sdf.parse("1927-12-31 23:54:07");\n Date date2 = sdf.parse("1927-12-31 23:54:08");\n\n long diff = date2.getTime() - date1.getTime();\n System.out.println("毫秒差:" + diff);\n // 预期1000,但得到……\n }\n}\n\n运行后——你看到的不是1000毫秒(1秒),而是353?甚至是负数?恭喜你,你遇到了1927年日期减法错误。
\n\n原因不在于Java的Bug(虽然也有关系,但稍后再说)。原因在于历史时区变更。1927年12月31日,在上海(Asia/Shanghai)发生了一件奇怪的事:当地时间23:54:08被调慢了5分52秒。实际上,那一秒并非1000毫秒,而只有353毫秒。Java忠实地反映了这一历史事实,但对开发者来说,这看起来就像魔法。
\n\n开发者常犯的常见错误
\n\n1. 盲目信任旧API(java.util.Date 和 SimpleDateFormat)
\n\n第一个也是最常见的错误是使用过时的类java.util.Date和SimpleDateFormat。它们不仅不方便,而且在处理历史日期时还隐藏着意外情况。
如何避免:使用java.time(Java 8+)。例如:
import java.time.LocalDateTime;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.time.format.DateTimeFormatter;\n\npublic class SafeDateDifference {\n public static void main(String[] args) {\n DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");\n ZoneId zone = ZoneId.of("Asia/Shanghai");\n\n LocalDateTime ldt1 = LocalDateTime.parse("1927-12-31 23:54:07", formatter);\n LocalDateTime ldt2 = LocalDateTime.parse("1927-12-31 23:54:08", formatter);\n\n ZonedDateTime zdt1 = ldt1.atZone(zone);\n ZonedDateTime zdt2 = ldt2.atZone(zone);\n\n long diff = zdt2.toInstant().toEpochMilli() - zdt1.toInstant().toEpochMilli();\n System.out.println("毫秒差:" + diff);\n // 仍然会得到奇怪数字,但至少你会知道原因!\n }\n}\n\n2. 忽略时区的历史变更
\n\n许多人认为时区只是相对于UTC的固定偏移。但实际上,在过去100年里,时区已经变更过数十次。