java - 魔法 00 :09 timezone with DatatypeFactory

标签 java xml calendar

在 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 时区。)看看这个奇怪的时区。

Timezone is broken

当我尝试将其转换回 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();

Unable to fix.

实际上我有一个针对我的特定程序的解决方法:现在对我有用的是我在导入 xml 时没有设置时区。 Date 然后在内部携带错误的时区,即 9 分钟。然后,当我最终想将 Date 导出回 xml 时,我将 xml 公历上的时区设置为 0,这神奇地修复了它并再次导出正确的 xml 格式。

但实际上,我想知道对于这种疯狂行为是否有任何好的解释。

最佳答案

我对日历历史和官方计时知之甚少,所以我通过首先确保我使用的是您的时区来测试它:

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 过渡的历史原因。我认为这只是科学 catch 来的问题,因为天文测量变得更加准确。

关于java - 魔法 00 :09 timezone with DatatypeFactory,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52370153/

相关文章:

java - 尝试为 DynamoDB 初始化客户端时 Amazon Lambda 超时

java - 两个 Web 应用程序指向 Sun glassfish 服务器中的相同 jndi

python - 在 Python 中处理 XML 真的很简单吗?

datetime - ISO 8601 日期时间表示

java - 月份数组抛出 ArrayIndexOutOfBoundException java

java - Java 中的复数求和函数

java - Spring Security 2 userDetailsS​​ervice 问题上的自定义身份验证提供程序

c# - XML XPath SelectSingleNode 问题

php - SimpleXML:获取属性可变的值

java - Android:唯一 ID 生成器和语言环境