跨EST/EDT时区比较Joda DateTime实例的相等性异常问题
问题根源:夏令时转换导致本地时间映射到同一UTC瞬间
这个问题的核心是美国纽约时区的夏令时结束规则,加上Joda DateTime的时间处理逻辑和equals()判定规则共同作用的结果。
1. Joda DateTime的equals()判定逻辑
Joda的DateTime.equals()方法只有在两个实例满足以下两个条件时才会返回true:
- 底层对应的UTC毫秒时间戳完全一致
- 使用的**时区(Chronology)**完全相同
只要这两点符合,哪怕显示的本地时间字符串看起来不一样,equals()也会判定相等。
2. 纽约时区2018年11月4日的夏令时转换细节
美国东部时区(America/New_York)在2018年11月4日凌晨2:00会结束夏令时,时钟会回拨1小时到1:00。这会导致两个关键现象:
- 本地时间
2018-11-04T01:00:00会出现两次:一次是夏令时(UTC-4),一次是标准时间(UTC-5) - 本地时间
2018-11-04T02:00:00是不存在的——时钟从1:59:59夏令时直接跳到1:00:00标准时间,跳过了2:00这个时间点
3. 拆解你的两个DateTime实例
实例A的生成过程
DateTime A = new DateTime(2018, 11, 4, 1, 00, 0).plusHours(1);
- 初始创建的
2018-11-04T01:00:00是夏令时的1点(UTC-4),对应UTC时间2018-11-04T05:00:00Z - 加1小时后,触发夏令时转换,Joda自动调整时区,最终得到的UTC瞬间是
2018-11-04T06:00:00Z,对应纽约标准时间的1:00(UTC-5),这就是A显示为2018-11-04T01:00:00.000-05:00的原因
实例B的生成过程
DateTime B = new DateTime(2018, 11, 4, 2, 00, 0);
- 你试图创建一个不存在的本地时间,Joda的处理规则是将这个无效时间映射到下一个有效的UTC瞬间,也就是
2018-11-04T06:00:00Z(和A的毫秒戳完全一致)。虽然显示字符串保留了你输入的02:00,但底层的实际时间瞬间已经和A对齐了。
4. 最终结论
A和B的UTC毫秒时间戳完全相同,且时区一致,所以equals()返回true。显示的本地时间不同只是Joda在处理无效时间时的字符串展示逻辑,不影响底层时间瞬间的判定。
内容的提问来源于stack exchange,提问作者Norcal




