为了账号安全,请及时绑定邮箱和手机立即绑定

神奇的 00:09 时区与 DatatypeFactory

神奇的 00:09 时区与 DatatypeFactory

MMTTMM 2021-09-26 16:55:37
在 java 中,有一个javax.xml.datatype.DatatypeFactory可用于导入和导出 xml 日期,如下所示。  String xmlDateIn = "1900-01-01T12:00:00";  DatatypeFactory df = DatatypeFactory.newInstance();  XMLGregorianCalendar xmlCalendar = df.newXMLGregorianCalendar(xmlDateIn);  String xmlDateOut = xmlCalendar.toXMLFormat();在这个简单的情况下xmlDateIn等于xmlDateOut,正如预期的那样。但如果我想要它,java.lang.Date事情就会变得有趣。  GregorianCalendar gregorianCalendar = xmlCalendar.toGregorianCalendar();  Date dts = gregorianCalendar.getTime();  System.out.println(dts);  // prints Mon Jan 01 12:00:00 CET 1900乍一看它仍然可以正常工作,但实际上内部某些东西似乎已损坏。使用我的 IDE,我可以看到Date对象内部发生了什么。(如果你想知道,我住在 CET 时区。)看看这个奇怪的时区。当我尝试将其转换回 XML 时,实际上也打印了 9 分钟时区。所以,这不仅仅是内部的事情。  DatatypeFactory df2 = DatatypeFactory.newInstance();  GregorianCalendar gc2 = new GregorianCalendar();  gc2.setTime(dts);  XMLGregorianCalendar xc2 = df2.newXMLGregorianCalendar(gc2);  System.out.println(xc2.toXMLFormat()); // prints 1900-01-01T12:00:00.000+00:09 为了修复它,如果我手动设置时区,事情会变得非常糟糕。看看这个神奇的时刻:  String xmlDateIn = "1900-01-01T12:00:00";  DatatypeFactory df = DatatypeFactory.newInstance();  XMLGregorianCalendar xmlCalendar = df.newXMLGregorianCalendar(xmlDateIn);  xmlCalendar.setTimezone(0);  // <--- ONLY CHANGE  GregorianCalendar gregorianCalendar = xmlCalendar.toGregorianCalendar();  Date dts = gregorianCalendar.getTime();实际上我对我的特定程序有一个解决方法:现在对我有用的是我在导入 xml 时没有设置时区。在Date随后进行了错误的时区内部,即9分钟。然后,当我最终想将其导出Date回 xml 时,我确实将 xml gregorian 日历上的时区设置为 0,这神奇地修复了它并再次导出正确的 xml 格式。但实际上,我想知道这种疯狂的行为是否有任何好的解释。
查看完整描述

2 回答

?
慕码人2483693

TA贡献1860条经验 获得超9个赞

我对日历历史和官方计时不太了解,所以我首先确保我使用的是您的时区来测试它:


int offset = (int) TimeUnit.HOURS.toMillis(1);

String[] ids = TimeZone.getAvailableIDs(offset);

TimeZone cet = Arrays.stream(ids).map(TimeZone::getTimeZone)

    .filter(tz -> tz.getDisplayName(false, TimeZone.SHORT).equals("CET"))

    .findFirst().orElseThrow(

        () -> new RuntimeException("No CET timezone found"));


TimeZone.setDefault(cet);

然后我检查了那个时区的一些内部运作。特别是,我打印了它的历史时间转换:


System.out.println("Transitions:");

cet.toZoneId().getRules().getTransitions().forEach(

    t -> System.out.println("  " + t));

前两个这样的转换打印为:


Transition[Overlap at 1891-03-15T00:01+00:12:12 to +00:09:21]

Transition[Overlap at 1911-03-11T00:00+00:09:21 to Z]

随后是祖鲁语 (Z) 和 UTC+01:00 之间的各种“手动”转换。


因此,1900 年的午夜实际上比 1912 年相应日期的午夜晚了 9 分 21 秒。


实际上,如果将年份更改为 1912,则不会看到 9 分钟的差异:


String xmlDateIn = "1912-01-01T12:00:00";

我一直无法找到 12:12 或 9:21 转换的历史原因。我认为这只是一个科学追赶的问题,因为天文测量变得更加准确。


查看完整回答
反对 回复 2021-09-26
  • 2 回答
  • 0 关注
  • 191 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信