将XMLGregorianCalendar转换为GregorianCalendar的正确方法



我有两个类。首先包含日历字段和整数字段(tz偏移量)。第二个包含XmlGregorianCalendar字段。我想比较一下第一类和第二类的日期。

Calendar cal1 = (Calendar) SerializationUtils.clone(firstClass.getDepartureDatetime());
cal1.add(Calendar.MINUTE, -firstClass.getDepartureTzOffset());
GregorianCalendar cal2 = secondClass.getDepartureDateTime().toGregorianCalendar();
cal2.add(Calendar.MINUTE, -secondClass.getDepartureDateTime().getTimezone());
if (LOGGER.isDebugEnabled()) {
                LOGGER.debug(" - Second  [" + DateFormat.getDateTimeInstance().format(cal2.getTime()) + "]");
                LOGGER.debug(" - First [" + DateFormat.getDateTimeInstance().format(cal1.getTime()) + "]");
}

我在这些类中设置了相同的日期(11月19日,9:00 AM GMT+1)。

根据不同的系统时区,它显示不同的结果(在GMT时区):

Debian Lenny, TZ is CET:

Second  [Nov 19, 2011 7:00:00 AM] - wrong!
First [Nov 19, 2011 8:00:00 AM] -right!

Win7, TZ是GMT+3:

Second  [Nov 19, 2011 8:30:00 AM] - wrong!
First [Nov 19, 2011 8:00:00 AM] -right!

我做错了什么?

谢谢。

一级和二级:

public class FirstClass implements Serializable {
    private static final long serialVersionUID = -1150341618306402800L;
    private Calendar departureDatetime;
    private Integer departureTzOffset;
    public Calendar getDepartureDatetime() {
        return departureDatetime;
    }
    public void setDepartureDatetime(Calendar departureDatetime) {
        this.departureDatetime = departureDatetime;
    }
    public Integer getDepartureTzOffset() {
        return departureTzOffset;
    }
    public void setDepartureTzOffset(Integer departureTzOffset) {
        this.departureTzOffset = departureTzOffset;
    }
}
public class SecondClass implements Serializable
{
    private final static long serialVersionUID = 12345L;
    protected XMLGregorianCalendar departureDateTime;
    public XMLGregorianCalendar getDepartureDateTime() {
        return departureDateTime;
    }
    public void setDepartureDateTime(XMLGregorianCalendar value) {
        this.departureDateTime = value;
    }
}
SerializationUtils是一个org.apache.commons.lang.SerializationUtils来自Apache commons-lang库。

当我们调用(Calendar) SerializationUtils.clone(firstClass.getDepartureDatetime())时,Timezone出现了问题。时区设置为服务器TZ,在比较时我们损失了一些小时。

你应该问自己的第一个问题:我要做什么?转换GregorianCalendar和XMLGregorianCalendar很容易:

GregorianCalendar gc;
XMLGregorianCalendar xc;
gc = xc.toGregorianCalendar();
xc = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);

但这似乎不是你问题的核心。您正在尝试执行时区转换吗?我认为,如果将转换转换为显示时间(因为这实际上是一个格式化问题),可以更容易地完成这些工作,利用GregorianCalendar和XMLGregorianCalendar都携带时区信息的事实,并摆脱两个helper类。

TimeZone cet = TimeZone.getTimeZone("CET");
TimeZone utc = TimeZone.getTimeZone("UTC");
GregorianCalendar gc = new GregorianCalendar();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
@Test
public void testNow() throws DatatypeConfigurationException {
  df.setTimeZone(gc.getTimeZone());
  log.info(" - Gregorian LOCAL [" + df.format(gc.getTime()) + "]");
  df.setTimeZone(cet);
  log.info(" - Gregorian CET [" + df.format(gc.getTime()) + "]");
  df.setTimeZone(utc);
  String gcs = df.format(gc.getTime());
  log.info(" - Gregorian UTC [" + df.format(gc.getTime()) + "]");
  XMLGregorianCalendar xc = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
  df.setTimeZone(xc.getTimeZone(0));
  log.info(" - XML RAW [" + df.format(xc.toGregorianCalendar().getTime()) + "]");
  df.setTimeZone(cet);
  log.info(" - XML CET [" + df.format(xc.toGregorianCalendar().getTime()) + "]");
  df.setTimeZone(utc);
  String xcs = df.format(xc.toGregorianCalendar().getTime());
  log.info(" - XML UTC [" + df.format(xc.toGregorianCalendar().getTime()) + "]");
  assertEquals(gcs, xcs);
}

或者您的问题实际上是对输入进行消毒。我看到您有一个departureTime变量,大概用于从世界各地的机场起飞的航班,您可能从一些没有明确时区信息的数据源获得它们,而是假设"机场的当地时间"。这样就可以解释helper类,但是在这种情况下,您应该在输入发生的地方对输入进行消毒。确定"机场的当地时间"有时会很棘手(一个国家可能会在明年晚一周选择从日光节约时间切换到标准时间,或者完全取消夏令时,一个机场甚至可能在美国切换时区,例如,县从东部到中部再回到东部的频率比你想象的要高)。您应该使用计算机的Locale数据库来解决这个问题,并避免尝试滚动您自己的时区算法。

相关内容

  • 没有找到相关文章

最新更新