鉴于格列高利历的开始日期是1582年10月15日,请考虑以下测试,请帮助我了解会发生什么:
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.xml.datatype.DatatypeFactory;
import org.junit.Test;
@Test
public void gregorianToDateConversion() {
GregorianCalendar calendar = null;
Date date = null;
calendar = new GregorianCalendar(1582, 9, 04);
date = calendar.getTime();
System.out.println("new GregorianCalendar(1582, 9, 4) -> calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date:" + date);
calendar = new GregorianCalendar(1582, 9, 05);
date = calendar.getTime();
System.out.println("\nnew GregorianCalendar(1582, 9, 5) -> calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date:" + date);
calendar = new GregorianCalendar(1582, 9, 14);
date = calendar.getTime();
System.out.println("\nnew GregorianCalendar(1582, 9, 14) -> calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date:" + date);
calendar = new GregorianCalendar(1582, 9, 15);
date = calendar.getTime();
System.out.println("\nnew GregorianCalendar(1582, 9, 15) -> calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date:" + date);
String dateToParse = null;
dateToParse = "1582-10-04";
System.out.println("\nString to parse: " + dateToParse);
calendar = parseDateTime(dateToParse);
if(calendar != null) {
date = calendar.getTime();
System.out.println("datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() -> \n calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date: " + date);
}
dateToParse = "1582-10-05";
System.out.println("\nString to parse: " + dateToParse);
calendar = parseDateTime(dateToParse);
if(calendar != null) {
date = calendar.getTime();
System.out.println("datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() -> \n calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date: " + date);
}
dateToParse = "1582-10-14";
System.out.println("\nString to parse: " + dateToParse);
calendar = parseDateTime(dateToParse);
if(calendar != null) {
date = calendar.getTime();
System.out.println("datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() -> \n calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date: " + date);
}
dateToParse = "1582-10-15";
System.out.println("\nString to parse: " + dateToParse);
calendar = parseDateTime(dateToParse);
if(calendar != null) {
date = calendar.getTime();
System.out.println("datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() -> \n calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date: " + date);
}
}
private GregorianCalendar parseDateTime(String s) {
DatatypeFactory datatypeFactory = null;
try {
datatypeFactory = DatatypeFactory.newInstance();
return datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
结果如下:
new GregorianCalendar(1582, 9, 4) -> calendar[DAY_OF_MONTH [4], MONTH [9], YEAR [1582]] **OK**
calendar.getTime() -> Date:Thu Oct 04 00:00:00 CET 1582 **OK**
new GregorianCalendar(1582, 9, 5) -> calendar[DAY_OF_MONTH [15], MONTH [9], YEAR [1582]] **+ 10 days ??**
calendar.getTime() -> Date:Fri Oct 15 00:00:00 CET 1582 **coherent with calendar**
new GregorianCalendar(1582, 9, 14) -> calendar[DAY_OF_MONTH [24], MONTH [9], YEAR [1582]] **+ 10 days ??**
calendar.getTime() -> Date:Sun Oct 24 00:00:00 CET 1582 **coherent with calendar**
new GregorianCalendar(1582, 9, 15) -> calendar[DAY_OF_MONTH [15], MONTH [9], YEAR [1582]] **OK**
calendar.getTime() -> Date:Fri Oct 15 00:00:00 CET 1582 **OK**
String to parse: 1582-10-04
datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() ->
calendar[DAY_OF_MONTH [4], MONTH [9], YEAR [1582]]
calendar.getTime() -> Date: Mon Sep 24 00:00:00 CET 1582 **Not coherent with calendar. Conversion to julian date?**
String to parse: 1582-10-05
datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() ->
calendar[DAY_OF_MONTH [5], MONTH [9], YEAR [1582]]
calendar.getTime() -> Date: Tue Sep 25 00:00:00 CET 1582 **Not coherent with calendar. Conversion to julian date?**
String to parse: 1582-10-14
datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() ->
calendar[DAY_OF_MONTH [14], MONTH [9], YEAR [1582]] **OK**
calendar.getTime() -> Date: Thu Oct 04 00:00:00 CET 1582 **Not coherent with calendar. Conversion to julian date?**
String to parse: 1582-10-15
datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() ->
calendar[DAY_OF_MONTH [15], MONTH [9], YEAR [1582]] **OK**
calendar.getTime() -> Date: Fri Oct 15 00:00:00 CET 1582 **OK**
你可以告诉我发生了什么吗?
非常感谢你。
编辑: 谢谢,我已经解决了我要解析的日期格式的错误:现在所有的都有yyyy-MM-gg格式,不再抛出任何异常。
现在我试着澄清我的配音。
是什么决定我们是否使用了预感格里高利历?
总结:
java.util.GregorianCalendar表示1582年10月15日之前的日期的朱利安日历和此日期之后的格里高利历。是不是?
因此,这证明了新GregorianCalendar(...)中的行为......
如果我这样做:
new GregorianCalendar(1582, 9, 4)
我有
calendar[DAY_OF_MONTH [4], MONTH [9], YEAR [1582]]
因为朱鹭日历中存在1582年10月4日,我创建的日历代表朱利安日期。
将此日历转换为日期,我们有:
Date:Thu Oct 04 00:00:00 CET 1582, consistent with Calendar.
如果我这样做:
new GregorianCalendar(1582, 9, 5)
我获得了
calendar[DAY_OF_MONTH [15], MONTH [9], YEAR [1582]]
因为10月5日在朱利安和格里高利历中都不存在。所以GregorianCalendar构造函数在10月4日之后的1天内创建了一个日期,这是格里高利历的第一天,即10月15日。然后用格里高历系统表示新日期
我将创建一个新日历,从(1582,9,5)到(1582,9,14)的日期相同。<Date:Fri Oct 15 00:00:00 CET 1582
如果我这样做:
new GregorianCalendar(1582, 9, 15)
我有
calendar[DAY_OF_MONTH [15], MONTH [9], YEAR [1582]]
因为10月15日存在于格里高利历中,新日期在此系统中表示。 转换为日期的日历再次保持一致:
Date:Fri Oct 15 00:00:00 CET 1582
这意味着GregorianCalendar构造函数假定我在日历系统中输入在给定时期内有效的日期:换句话说假设如果我输入的日期早于或等于10月4日,我认为根据朱利安日历的日期和日期在本系统中表示,如果我输入10月5日至14日之间的日期,则计算朱利安日历结束日期(10月4日)与我输入日期之间的天数,并将其总和天数到格里高历(10月15日)的开始日期,并用格里高利系统表示新日期,如果我输入10月15日之后的日期,则假定我输入的日期是格里高利历,新日期是在这个系统中表达。
这一切都正确吗?
这不是一种预防行为,对吗?如果日历是一个普通的格里高利历,我希望用
new GregorianCalendar(1582, 9, 5)
我会得到
calendar[DAY_OF_MONTH [5], MONTH [9], YEAR [1582]]
如果格里高利系统中不存在日期,那么10月5日也会被设置,如果是格里高利历的第一天10天,它将等于朱利安日期9月25日,如果我&#39 ;我没弄错。解析字符串并创建一个通过XmlGregorianCalendar的新GregorianCalendar,这种行为在我看来与众不同。
解析&#34; 1582-10-04&#34;我获得了
calendar[DAY_OF_MONTH [4], MONTH [9], YEAR [1582]]
(与上面的示例相同..)但是日期
Date: Mon Sep 24 00:00:00 CET 1582
(这里我们有一个朱利安日期,是不是?但在上面的例子中(GregorianCalendar由其构造函数创建),Date等于Calendar。为什么现在它不同?
解析字符串&#34; 1582-10-05&#34;我们有
calendar[DAY_OF_MONTH [5], MONTH [9], YEAR [1582]]
(现在我们有一个Proleptic格里高利历,对吗?)
但又是一个不同的日期
Date: Tue Sep 25 00:00:00 CET 1582 (Julian Date? Why?)
相同的行为解析&#34; 1582-10-14&#34;
calendar[DAY_OF_MONTH [14], MONTH [9], YEAR [1582]]
Date: Thu Oct 04 00:00:00 CET 1582
如果我们最终解析&#34; 1582-10-15&#34;,我们回到格里高利时代广告就变得一致:
calendar[DAY_OF_MONTH [15], MONTH [9], YEAR [1582]]
Date: Fri Oct 15 00:00:00 CET 1582
你能帮助我理解所有这些行为吗? 非常感谢你。
编辑2:
感谢您的回答,如果对我有疑问的话。 我尝试了以下代码:
GregorianCalendar proleptic = new GregorianCalendar();
proleptic.setGregorianChange(new Date(Long.MIN_VALUE));
proleptic.set(Calendar.DAY_OF_MONTH, 5);
proleptic.set(Calendar.MONTH, 9);
proleptic.set(Calendar.YEAR, 1582);
System.out.println("proleptic [DAY_OF_MONTH ["+proleptic.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+proleptic.get(Calendar.MONTH)+"], YEAR ["+proleptic.get(Calendar.YEAR)+"]");
Date prolepticDate = proleptic.getTime();
System.out.println("prolepticDate ["+prolepticDate+"]");
输出结果为:
proleptic [DAY_OF_MONTH [5], MONTH [9], YEAR [1582]
prolepticDate [Tue Sep 25 00:24:07 CET 1582]
现在我的DAY_OF_MONTH日历与我设定的日历一致,所以我认为这是一种预感行为,对吧? 但我再次问为什么getTime()方法获得的Date不代表同一天,而是10天前。 再次感谢。
编辑3:
问题对我来说有点清楚,但并不完全。 我没有详细了解从GregorianCalendar到Date的转换是什么逻辑以及为什么一个预感格里高利历和一个传统的日历和每个日历都使用与DAY,MONTH和YEAR相同的参数构建,并不总是代表同一时刻。 我做了一些进一步的测试。
GregorianCalendar proleptic = null;
GregorianCalendar calendar = null;
Date date = null;
// ---- JULIAN PERIOD ----
proleptic = new GregorianCalendar();
proleptic.clear();
proleptic.setGregorianChange(new Date(Long.MIN_VALUE));
proleptic.set(Calendar.DAY_OF_MONTH, 5);
proleptic.set(Calendar.MONTH, Calendar.FEBRUARY);
proleptic.set(Calendar.YEAR, 1582);
System.out.println("proleptic_calendar_5Feb1582 [DAY_OF_MONTH ["+proleptic.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+proleptic.get(Calendar.MONTH)+"], YEAR ["+proleptic.get(Calendar.YEAR)+"]");
date = proleptic.getTime();
System.out.println("date_5Feb1582 from proleptic ["+date+"]");
calendar = new GregorianCalendar(1582, 1, 5);
date = calendar.getTime();
System.out.println("new GregorianCalendar(1582, 1, 5) -> [DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("new GregorianCalendar(1582, 1, 5) .getTime() -> Date:" + date);
System.out.println("proleptic_calendar_5Feb1582 in millis ["+proleptic.getTimeInMillis()+"], new GregorianCalendar(1582, 1, 5) in millis ["+calendar.getTimeInMillis()+"], millis are equal ["+ (proleptic.getTimeInMillis() == calendar.getTimeInMillis()) +"]");
//--------
System.out.println("\n");
// ---- transition period ----
proleptic = new GregorianCalendar();
proleptic.clear();
proleptic.setGregorianChange(new Date(Long.MIN_VALUE));
proleptic.set(Calendar.DAY_OF_MONTH, 8);
proleptic.set(Calendar.MONTH, Calendar.OCTOBER);
proleptic.set(Calendar.YEAR, 1582);
System.out.println("proleptic_calendar_8Oct1582 [DAY_OF_MONTH ["+proleptic.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+proleptic.get(Calendar.MONTH)+"], YEAR ["+proleptic.get(Calendar.YEAR)+"]");
date = proleptic.getTime();
System.out.println("date_5Oct1582 from proleptic ["+date+"]");
calendar = new GregorianCalendar(1582, 9, 8);
date = calendar.getTime();
System.out.println("new GregorianCalendar(1582, 9, 8) -> [DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("new GregorianCalendar(1582, 9, 8) .getTime() -> Date:" + date);
System.out.println("proleptic_calendar_8Oct1582 in millis ["+proleptic.getTimeInMillis()+"], new GregorianCalendar(1582, 9, 8) in millis ["+calendar.getTimeInMillis()+"], millis are equal ["+ (proleptic.getTimeInMillis() == calendar.getTimeInMillis()) +"]");
//--------
System.out.println("\n");
// ---- GREGORIAN PERIOD ----
proleptic = new GregorianCalendar();
proleptic.clear();
proleptic.setGregorianChange(new Date(Long.MIN_VALUE));
proleptic.set(Calendar.DAY_OF_MONTH, 5);
proleptic.set(Calendar.MONTH, Calendar.DECEMBER);
proleptic.set(Calendar.YEAR, 1582);
System.out.println("proleptic_calendar_5Dec1582 [DAY_OF_MONTH ["+proleptic.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+proleptic.get(Calendar.MONTH)+"], YEAR ["+proleptic.get(Calendar.YEAR)+"]");
date = proleptic.getTime();
System.out.println("date_5Dec1582 from proleptic ["+date+"]");
calendar = new GregorianCalendar(1582, 11, 5);
date = calendar.getTime();
System.out.println("new GregorianCalendar(1582, 11, 5) -> [DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("new GregorianCalendar(1582, 11, 5) .getTime() -> Date:" + date);
System.out.println("proleptic_calendar_5Dec1582 in millis ["+proleptic.getTimeInMillis()+"], new GregorianCalendar(1582, 11, 5) in millis ["+calendar.getTimeInMillis()+"], millis are equal ["+ (proleptic.getTimeInMillis() == calendar.getTimeInMillis()) +"]");
//--------
输出结果为:
proleptic_calendar_5Feb1582 [DAY_OF_MONTH [5], MONTH [1], YEAR [1582]
date_5Feb1582 from proleptic [Fri Jan 26 00:00:00 CET 1582]
new GregorianCalendar(1582, 1, 5) -> [DAY_OF_MONTH [5], MONTH [1], YEAR [1582]]
new GregorianCalendar(1582, 1, 5) .getTime() -> Date:Mon Feb 05 00:00:00 CET 1582
proleptic_calendar_5Feb1582 in millis [-12241069200000], new GregorianCalendar(1582, 1, 5) in millis [-12240205200000], millis are equal [false]
proleptic_calendar_8Oct1582 [DAY_OF_MONTH [8], MONTH [9], YEAR [1582]
date_5Oct1582 from proleptic [Fri Sep 28 00:00:00 CET 1582]
new GregorianCalendar(1582, 9, 8) -> [DAY_OF_MONTH [18], MONTH [9], YEAR [1582]]
new GregorianCalendar(1582, 9, 8) .getTime() -> Date:Mon Oct 18 00:00:00 CET 1582
proleptic_calendar_8Oct1582 in millis [-12219901200000], new GregorianCalendar(1582, 9, 8) in millis [-12219037200000], millis are equal [false]
proleptic_calendar_5Dec1582 [DAY_OF_MONTH [5], MONTH [11], YEAR [1582]
date_5Dec1582 from proleptic [Sun Dec 05 00:00:00 CET 1582]
new GregorianCalendar(1582, 11, 5) -> [DAY_OF_MONTH [5], MONTH [11], YEAR [1582]]
new GregorianCalendar(1582, 11, 5) .getTime() -> Date:Sun Dec 05 00:00:00 CET 1582
proleptic_calendar_5Dec1582 in millis [-12214890000000], new GregorianCalendar(1582, 11, 5) in millis [-12214890000000], millis are equal [true]
第一次测试(1582年2月5日)是指属于朱利安历法的时期,第二次测试(1582年10月8日)属于过渡期,第三次测试(1582年12月5日)属于公历期。 然后我想要注意以下事项:
朱利安时期
过渡期
格里高利时期
您能帮助我逐一解释所有这些结果吗?
感谢。
答案 0 :(得分:2)
方法newXMLGregorianCalendar(s)
必须使用格式为&#34; yyyy-MM-dd&#34;的字符串,即使用两个月的数字。但是你已经定义了字符串&#34; 1582-10-4&#34;和&#34; 1582-10-5&#34; (而不是&#34; 1582-10-04&#34;和&#34; 1582-10-05&#34;)。
我已经测试了更换件,但它确实有效。
请记住,XMLGregorianCalendar非常严格,并且根据ISO-8601中的标准惯例使用了预感格里高利历。这意味着,它甚至在1582年之前使用格里高利闰年规则。这解释了你的陈述&#34;与日历不一致。转换为朱利安日期?&#34;。例如:
教皇在1582-10-04(旧朱利安历法)之后的10天内删除了,所以在此之后1582-10-15的日期紧接着是新的格里高利历。在预感格里高利历中,日期1582-10-14是明确定义的,对应于1582-10-15之前的一天,因此(历史朱利安)日期为1582-10-04。
OP编辑后的更新:
您问题的简单答案&#34;是什么决定了我们是否使用了预感格里高利历?&#34;是:你决定。
详细信息:如果您使用XMLGregorianCalendar
,则使用预感格里高利历。
如果您使用java.util.GregorianCalendar
,那么您默认选择日期1582-10-15作为格里历日历的第一天。所有以前的日子都被认为是朱利安历法。但是,您可以覆盖默认的切换日期。为此,您只需使用适当的参数调用方法setGregorianChange(Date)即可。 new Date(Long.MIN_VALUE)
的参数设置了预感格里高利历,而new Date(Long.MAX_VALUE)
的参数设定了预知的朱利安历法。
同样重要的是要注意
a)大多数国家在1582-10-15(仅主要的天主教国家)没有改为格里高历,
b)历史日期进一步由其他因素决定,例如不同年份的开始(这使得JDK中的整个julian-gregorian-calendar-implementation完全不足 - 目前没有提供支持的库)。编辑后更新:
输出proleptic [DAY_OF_MONTH [5], MONTH [9], YEAR [1582]
与预期一致,并保存输入,如在预感格里高利历中定义的那样(1582-10-15之前的10天,向后应用格里高利闰年规则)。
输出prolepticDate [Tue Sep 25 00:24:07 CET 1582]
是一个完全不同的故事。但是如果你记得你真的在toString()
上调用方法java.util.Date
,这是可以理解的。 此方法在内部实例化一个新的格里历日历对象,默认开关为1582-10-15。一个Date
- 对象不知道(也没有内部状态)关于设置格里高利的日期更改,因此其toString()
- 方法只应用默认值。最后,仅以Date.toString()
的特定格式重新计算/重新格式化为具有日期表示的朱利安日历对象。即:1582-09-25(转换前十天)。
由于@VGR的评论更新:
我的测试验证了例如对于预感日期1582-10-05,XMLGregorianCalendar
和新GregorianCalendar
的专门构造产生了与unix-epoch相同的毫秒时间,请参见此处:
String s = "1582-10-05";
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
GregorianCalendar xml = datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar();
GregorianCalendar proleptic = new GregorianCalendar();
proleptic.clear(); // very important for proper comparison to reset time part to zero
proleptic.setGregorianChange(new Date(Long.MIN_VALUE));
proleptic.set(Calendar.DAY_OF_MONTH, 5);
proleptic.set(Calendar.MONTH, Calendar.OCTOBER);
proleptic.set(Calendar.YEAR, 1582);
boolean isEqual = (xml.getTimeInMillis() == proleptic.getTimeInMillis());
System.out.println("XML-millisSinceEpoch: " + xml.getTimeInMillis());
System.out.println("Proleptic-millisSinceEpoch: " + proleptic.getTimeInMillis());
System.out.println("XML==Proleptic (1582-10-05): " + isEqual);
System.out.println(
"proleptic [DAY_OF_MONTH [" + proleptic.get(Calendar.DAY_OF_MONTH) + "], MONTH ["
+ proleptic.get(Calendar.MONTH) + "], YEAR [" + proleptic.get(Calendar.YEAR) + "]"
);
System.out.println("Date.toString() [" + proleptic.getTime() + "]");
输出:
XML-millisSinceEpoch: -12220160400000
Proleptic-millisSinceEpoch: -12220160400000
XML==Proleptic (1582-10-05): true
proleptic [DAY_OF_MONTH [5], MONTH [9], YEAR [1582]
Date.toString() [Tue Sep 25 00:00:00 CET 1582]