多重问题
- 1 day difference:已经在其他答案中解释的时区,即,例如,时区
Europe/Berlin
的午夜对应于前一天的23:00在UTC
(不是夏令时)
- 一百零四:旧的班级(
Date
,SimpleDateFormat
,Calendar
)使用儒略历直到1582年10月,而java.time
中的new个班级使用预言格里高利历
从Wikipedia我们可以看出两者之间的区别,下面的代码证实了这一点:
TimeZone.setDefault(TimeZone.getTimeZone("UTC")); // one error less
for (var year : List.of(1, 101, 201, 1401, 1501, 1601)) {
var date = new Date(year-1900, 0, 10);
var instant = date.toInstant();
System.out.println(date.getTime() + " = " + date);
System.out.println(instant.toEpochMilli() + " = " + instant);
System.out.println();
}
输出:
-62134992000000 = Mon Jan 10 00:00:00 UTC 1
-62134992000000 = 0001-01-08T00:00:00Z
-58979232000000 = Sun Jan 10 00:00:00 UTC 101
-58979232000000 = 0101-01-09T00:00:00Z
-55823472000000 = Sat Jan 10 00:00:00 UTC 201
-55823472000000 = 0201-01-10T00:00:00Z
-17954352000000 = Mon Jan 10 00:00:00 UTC 1401
-17954352000000 = 1401-01-19T00:00:00Z
-14798592000000 = Sun Jan 10 00:00:00 UTC 1501
-14798592000000 = 1501-01-20T00:00:00Z
-11643696000000 = Wed Jan 10 00:00:00 UTC 1601
-11643696000000 = 1601-01-10T00:00:00Z
Java 多克
我们可以在文档中找到差异的解释(重点添加):
- GregorianCalendar
在历史上,在那些最先采用公历的国家,1582年10月4日(儒略)紧随其后,1582年10月15日(公历)紧随其后.这个日历正确地模拟了这一点.在公历转换之前,公历实施儒略历.公历和儒略历之间的唯一区别是闰年规则.The Julian calendar specifies leap years every four years, whereas the Gregorian calendar omits century years which are not divisible by 400.
- java.time
这里定义的类表示主要的日期-时间概念,包括瞬间、持续时间、日期、时间、时区和周期.他们是based on the ISO calendar system,这是继proleptic Gregorian rules之后事实上的世界日历.
结论
If dealing with dates after 1582, Date#toInstant
, Instant#atOffset
(Instant#atZone
) and OffsetDateTime#toLocalDate
(ZonedDateTime#toLocalDate
) can be used, taking care to use the correct time zone (offset.) Anyway, as already warned, using these classes is strongly discouraged!
Otherwise, for dates before/at 1582, you will need to first check which calendar was (should be) used to represent these dates.
对于儒略历(1583年之前),正如我已经 comments 过的,可以使用以下或类似的代码:
var calendar = Calendar.getInstance();
calendar.setTime(date);
var localDate = LocalDate.of(
calendar.get(Calendar.YEAR),
1 + calendar.get(Calendar.MONTH), // months are 0-based
calendar.get(Calendar.DAY_OF_MONTH));