在200年左右将Dates转换为LocalDates时,我得到的结果不一致.使用以下代码进行转换:
- private LocalDate toLocalDate(Date localDate)
- {
- return LocalDateTime.ofInstant(localDate.toInstant(),ZoneId.systemDefault()).toLocalDate();
- }
我的ZoneId.systemDefault()是非洲/哈拉雷,它与测试中使用的CAT相匹配.我运行的测试用例是
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy",Locale.US);
- String dateString = "Tue Jan 01 00:00:00 CAT 200";
- String dateString2 = "Tue Jan 01 00:00:00 CAT 201";
- String dateString3 = "Wed Dec 31 00:00:00 CAT 200";
- System.out.println(toLocalDate(simpleDateFormat.parse(dateString)));
- System.out.println(toLocalDate(simpleDateFormat.parse(dateString2)));
- System.out.println(toLocalDate(simpleDateFormat.parse(dateString3)));
我的预期输出是
- 0200-01-01
- 0201-01-01
- 0200-12-31
或者,如果不是这样,至少始终不正确的值.实际结果是
- 0199-12-31
- 0201-01-01
- 0200-12-31
所以似乎第一个稍微回滚,可能是两个小时对应的CAT时区?但为什么这只发生在一个案例上呢?对2000年进行相同的实验不会产生相同的错误.
解决方法
斯蒂芬在评论中提供了解释.基本上,java.util.Date使用日历系统,该系统在1582年的
Julian calendar system和
Gregorian calendar system之间切换,跳过10天.因此,1582年或之前的日期将出现差异 – 但差异的大小将随时间变化 – 平均每400年3天.碰巧在200到400AD之间,你没有看到这个,因为这与差异为0时相对应.
这是一个简短但完整的程序来演示这个问题:
- import java.time.*;
- import java.util.*;
- public class Test {
- public static void main(String[] args) throws Exception {
- // Value obtained with Noda Time: should be 0199-12-31T22:00:00Z.
- long millis = -55855792800000L;
- Instant instant = Instant.ofEpochMilli(millis);
- Date date = new Date(millis);
- System.out.println(instant);
- System.out.println(date);
- }
- }
我机器上的输出:
- 0199-12-31T22:00:00Z
- Tue Jan 01 22:00:00 GMT 200
这一点很复杂,你的初始代码中假设CAT和非洲/哈拉雷是相同的(在那个时间点,非洲/哈拉雷被认为有02:10的偏移)和你的字符串中错误的日期名称 – 但这是Java中导致此问题的错误.
我建议你使用java.time.format类执行所有的解析 – 然后我希望你不会得到这种不一致.