You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ZonedDateTime与XMLGregorianCalendar互转后对象不匹配的问题咨询

ZonedDateTime与XMLGregorianCalendar互转后对象不匹配的问题咨询

我最近写了个Java时间类互转的测试用例,结果最后一个断言总是失败,实在搞不懂原因,来请教下大家!

先贴我的测试代码:

@Test 
public void test_calendar() throws DatatypeConfigurationException { 
    ZonedDateTime zdt = ZonedDateTime.now(); 
    GregorianCalendar gc = GregorianCalendar.from(zdt); 
    XMLGregorianCalendar xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc); 

    assertThat(gc.toZonedDateTime(), comparesEqualTo(zdt)); 
    assertThat(xgc.toGregorianCalendar(), comparesEqualTo(gc)); 
    assertThat(xgc.toGregorianCalendar().toZonedDateTime(), comparesEqualTo(zdt)); // <== 这里失败
}

失败时的错误提示是:

Expected: a value equal to <2025-06-19T18:13:44.885-05:00[America/Chicago]>
but: <2025-06-19T18:13:44.885-05:00[GMT-05:00]> was greater than <2025-06-19T18:13:44.885-05:00[America/Chicago]>

我能看出来是时区不匹配导致的,但有点懵:为什么gc.toZonedDateTime()和xgc.toGregorianCalendar()这两步的断言都能通过,偏偏最后一步转回来就不行了?


这问题我之前也踩过坑,其实是XMLGregorianCalendar的时区存储机制在搞事情:

  • 首先,GregorianCalendar.from(zdt)转出来的gc是带着完整时区ID(比如America/Chicago)的,所以gc.toZonedDateTime()能完美还原出和原zdt一致的对象,这一步断言自然没问题。
  • 但当你把gc转成XMLGregorianCalendar时,它并不会存储完整的时区ID,只会记录时区的偏移量(比如GMT-05:00),不会保留America/Chicago这种包含夏令时规则的时区标识。
  • 那为什么xgc.toGregorianCalendar()和原gc的断言能通过?因为GregorianCalendar的equals方法比较宽松,只要时间戳、偏移量、日历字段都一致,哪怕时区ID不一样也会返回true。
  • 而ZonedDateTime的equals方法就严格多了,它不仅要比对时间和偏移量,还要求时区ID完全匹配,所以最后一步转出来的ZonedDateTime用的是偏移量时区,和原zdt的时区ID不匹配,断言就失败了。

如果要保证转回来的对象完全匹配,给你个小技巧:在把XMLGregorianCalendar转回GregorianCalendar之后,手动设置回原来的时区ID:

// 先保存原时区
ZoneId originalZone = zdt.getZone();
// 从XMLGregorianCalendar转回GregorianCalendar
GregorianCalendar convertedGc = xgc.toGregorianCalendar();
// 手动设置回原时区ID
convertedGc.setTimeZone(TimeZone.getTimeZone(originalZone));
// 这时候再转ZonedDateTime就和原对象一致了
assertThat(convertedGc.toZonedDateTime(), comparesEqualTo(zdt));

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 08:39:33