将日期转换为 LocalDate 在公元 200 年左右返回奇怪的结果
Converting Date to LocalDate returning strange results around 200AD
在 200 年左右将 Date
s 转换为 LocalDate
s 时,我得到的结果不一致。使用以下代码进行转换:
private LocalDate toLocalDate(Date localDate)
{
return LocalDateTime.ofInstant(localDate.toInstant(), ZoneId.systemDefault()).toLocalDate();
}
我的ZoneId.systemDefault()
是Africa/Harare
,与测试中使用的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 and the Gregorian calendar system 之间切换,跳过 10 天。因此,1582 年或之前的日期会出现差异 - 但差异的大小会随时间变化 - 平均每 400 年出现 3 天。碰巧在公元 200 到 400 年之间,您没有看到这个,因为这对应于差异为 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 和 Africa/Harare 相同的初始代码中的问题(在那个时间点,Africa/Harare 被认为具有 +02 的偏移量: 10) 以及您的字符串中不正确的日期名称 - 但这是 Java 中的错误导致了这里的问题。
我建议您使用 java.time.format
类 执行所有解析 - 然后我 希望 您不会遇到这种不一致。
在 200 年左右将 Date
s 转换为 LocalDate
s 时,我得到的结果不一致。使用以下代码进行转换:
private LocalDate toLocalDate(Date localDate)
{
return LocalDateTime.ofInstant(localDate.toInstant(), ZoneId.systemDefault()).toLocalDate();
}
我的ZoneId.systemDefault()
是Africa/Harare
,与测试中使用的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 and the Gregorian calendar system 之间切换,跳过 10 天。因此,1582 年或之前的日期会出现差异 - 但差异的大小会随时间变化 - 平均每 400 年出现 3 天。碰巧在公元 200 到 400 年之间,您没有看到这个,因为这对应于差异为 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 和 Africa/Harare 相同的初始代码中的问题(在那个时间点,Africa/Harare 被认为具有 +02 的偏移量: 10) 以及您的字符串中不正确的日期名称 - 但这是 Java 中的错误导致了这里的问题。
我建议您使用 java.time.format
类 执行所有解析 - 然后我 希望 您不会遇到这种不一致。