我想解析java.util.Datejava.time.LocalDate 当我搜索问题时,我发现了以下代码:

Date date = new SimpleDateFormat("dd.MM.yyyy").parse("01.01.0001");
date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

如果我将01.01.0001作为开始日期,我就会遇到问题:

date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

==同步,由Elderman更正==@elder_man

29.12.000001.01.0001是不同的.

  1. 为什么实际结果和预期的不一样?
  2. 如果我还想收到值为01.01.0001LocalDate,我该怎么办?

有关时区的信息:

ZoneId.systemDefault()

==>(java.time.ZoneRegion)欧洲/柏林

  1. 我认为,问题是这一步:date.toInstant()
  2. 我不认为这只是一个时区问题.如果我用不同的年份来测试它.例如1901,则以31.12.1900结束.
        Date date0001 = new SimpleDateFormat("dd.MM.yyyy").parse("01.01.0001");
        System.out.println(date0001.toInstant());

==>0000-12-29T23:00:00Z

        Date date1901 = new SimpleDateFormat("dd.MM.yyyy").parse("01.01.1901");
        System.out.println(date1901.toInstant());

==>1900-12-31T23:00:00Z

推荐答案

多重问题

  • 1 day difference:已经在其他答案中解释的时区,即,例如,时区Europe/Berlin的午夜对应于前一天的23:00在UTC(不是夏令时)
  • 一百零四:旧的班级(DateSimpleDateFormatCalendar)使用儒略历直到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));

Java相关问答推荐

Java:根据4象限中添加的行数均匀分布行的公式

Java List with all combinations of 8 booleans

嵌入式ActiveMQ Artemis Web控制台加载错误

Java 21 struct 化连接货币,需要可预知的子任务异常排序

不推荐使用的Environment.getExternalStorageDirectory().getAbsolutePath()返回的值不同于新的getExternalFilesDir(空)?

由于我在Main方法中关闭了 scanner ,但在该方法中创建了一个新的 scanner ,因此出现了错误

为什么当我创建Robot对象时,JavaFX引发IlLegalStateException异常?

Spring-Boot Kafka应用程序到GraalVM本机映像-找不到org.apache.kafka.streams.processor.internals.DefaultKafkaClientSupplier

二进制数据的未知编码/序列化

如何从HttpResponse实例获取Entity对象的内容?

无法将GSON导入到我的JavaFX Maven项目

从Spring6中的JPMS模块读取类时出现问题

如果执行@BeForeEach#repository.save(),则测试中的UnitTest最终UUID会发生更改

在不使用instanceof或强制转换的情况下从父类变量调用子类方法

将@Transactional添加到Spring框架中链下的每个方法会产生什么效果?

如何在Java上为循环数组从synchronized迁移到ReentrantLock

java构造函数中的冻结操作何时发生?

如何在Java中正确实现填字游戏求解器

为什么 Random() 的行为不符合预期?

有没有办法仅将 JComboBox 中的选定项目居中(因此保持组合框中的所有项目左对齐)