Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么使用Instant将1582之前的Java日期转换为LocalDate会给出不同的日期?_Java_Date_Datetime_Java 8_Java Time - Fatal编程技术网

为什么使用Instant将1582之前的Java日期转换为LocalDate会给出不同的日期?

为什么使用Instant将1582之前的Java日期转换为LocalDate会给出不同的日期?,java,date,datetime,java-8,java-time,Java,Date,Datetime,Java 8,Java Time,考虑以下代码: Date date = new SimpleDateFormat("MMddyyyy").parse("01011500"); LocalDate localDateRight = LocalDate.parse(formatter.format(date), dateFormatter); LocalDate localDateWrong = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).t

考虑以下代码:

Date date = new SimpleDateFormat("MMddyyyy").parse("01011500");

LocalDate localDateRight = LocalDate.parse(formatter.format(date), dateFormatter);
LocalDate localDateWrong = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).toLocalDate();

System.out.println(date);           // Wed Jan 01 00:00:00 EST 1500
System.out.println(localDateRight); // 1500-01-01
System.out.println(localDateWrong); // 1500-01-10
我知道1582年是儒略历和格里高利历的分界点。我不知道为什么会发生这种情况,或者如何适应它

以下是我到目前为止得出的结论:

  • 日期对象的
    basecalendar
    设置为
    JulianCalendar
  • date.toInstant()
    只返回
    Instant.ofEpochMilli(getTime())
  • date.getTime()
    返回-1483097400000
  • -1483097400000是星期三,格林威治时间1月10日下午5:00:00格里高利

因此,
getTime()
返回的毫秒数似乎是错误的(不太可能),或者只是与我预期的不同,我需要解释这种差异

LocalDate
仅处理前公历。从其:

ISO-8601日历系统是使用的现代民用日历系统 今天在世界大部分地区。它相当于proleptic 公历制,其中今天的闰年规则是 一直在申请。对于今天编写的大多数应用程序 ISO-8601规则完全适用。但是,任何应用程序 利用历史日期,并要求其准确 发现ISO-8601方法不合适

相比之下,旧的
java.util.GregorianCalendar
类(也间接用于
java.util.Date
的toString()-输出)使用可配置的公历截止日期,默认为1582-10-15,作为儒略历和公历规则之间的分隔日期

因此,
LocalDate
不能用于任何类型的历史日期

但请记住,即使是
java.util.Gregoriacalendar
配置了正确的区域相关截止日期,也常常会失败。例如,英国在1752年之前的3月25日开始了这一年。在许多国家,还有更多的历史偏差。在引入公历之前,在欧洲以外甚至连儒略历都不可用(或者只能从殖民主义的角度使用)

由于评论中的问题而更新:

<>解释值<代码> -14830974000000 让我们考虑下面的代码及其输出:

SimpleDateFormat format = new SimpleDateFormat("MMddyyyy", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("America/New_York"));
Date d = format.parse("01011500");

long t1500 = d.getTime();
long tCutOver = format.parse("10151582").getTime(); 
System.out.println(t1500); // -14830974000000
System.out.println(tCutOver); // default gregorian cut off day in "epoch millis"
System.out.println((tCutOver - t1500) / 1000); // output: 2611699200 = 30228 * 86400
需要注意的是,由于
美国/纽约
UTC
之间的时区偏移差异,您之前的评论中提到的值
-12219292800000升
tCutOver
相差5小时。所以在美国东部时区(美国/纽约),我们正好有30228天的时差。对于所讨论的时间跨度,我们应用儒略历法的规则,即每四年是闰年

在1500和1582之间,我们有82*365天+21闰日。然后我们还要在1582-01-01和1582-10-01之间增加273天,最后是4天,直到切换(记住10月4日之后是10月15日)。总计:82*365+21+273+4=30228(有待证明)

请向我解释为什么您期望的值与-1483097400000毫秒不同。这对我来说似乎是正确的,因为它处理了系统的时区偏移、1582年之前的儒略历规则以及从1582年10月4日跳到1582-10-15日期的转换。那么您的问题是什么“我如何告诉date对象将ms返回到正确的公历日期?”已经得到回答-无需更正。请记住,这种复杂的东西在生产使用中需要相当长的时间,并且可以在这么多年后正常工作

如果你真的想用JSR-310来做这件事,我重复一遍,没有对gregorian转换日期的支持。最好的事情是你可以自己处理

例如,您可能会考虑自发布0.9以来的外部库,其中包含一个前置朱利安日历。但它仍然是您处理旧朱利安日历和新公历日历之间的切换的努力。(由于新年开始等许多其他原因,不要期望这些图书馆能够处理真实的历史日期。)


2017年更新:另一个更强大的选择是使用我的库,它处理的不仅仅是朱利安/格里高利的转换。

请记住,在转换过程中有几个“它不计算”的日期,因为日历提前了。所以任何在“不真实日期”中的日期如果未标记为完全错误,则范围将被任意解析为“真实”日期。感谢提醒!这尤其适用于公历截止日期之前的任何日期。“公历截止日期”不是很好的定义。新日历采用大约需要500年。不同的日历实现可能使用不同的日期,因为特定的日期是相当随意的。它在date类中定义得很好。从
gregorianCutoff
字段的注释中:“默认值为1582年10月15日(Gregorian)00:00:00 UTC或-12219292800000升。对于此值,1582年10月4日(朱利安)后接1582年10月15日(格里高利)。”这是有道理的。那么为什么Date对象返回-14830974000000ms,这是错误的公历ms,或者为什么asInstant函数没有考虑Date对象的基准日历?对我来说更重要的是,我如何告诉Date对象将ms返回到正确的公历日期?@Rickhanloni看到了我更新的答案。顺便问一下,什么您管理的数据类型?历史事件的日期?我只是好奇。@RickHanlonII关于
date.toInstant()
,“自UNIX纪元起的毫秒数”的概念与日历规则无关。撇开其中使用的固定转换因子(一天=86400*1000毫秒)朱利安历法和公历历法之间没有变化,在这样的机器秤上也没有转换跳跃。