Правильный способ конвертировать XMLGregorianCalendar в GregorianCalendar - PullRequest
3 голосов
/ 17 ноября 2011

У меня есть 2 класса. Первый содержит поле календаря и поле целых чисел (смещение 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()) + "]");
}

Я установил равные даты (19 ноября, 9:00 по Гринвичу + 1) в этих классах.

В зависимости от системы TZ он показывает разные результаты (в GMT TZ):

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!

Что я делаю не так?

Спасибо.

UPDATE

1-й и 2-й классы:

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 lib.

Ответы [ 2 ]

1 голос
/ 18 ноября 2011

Была проблема с часовым поясом, когда мы вызываем (Calendar) SerializationUtils.clone (firstClass.getDepartureDatetime ()). Часовой пояс был установлен на сервере TZ, и мы потеряли несколько часов во время сравнения.

0 голосов
/ 17 ноября 2011

Первый вопрос, который вы должны задать себе: что я пытаюсь сделать?Преобразовать GregorianCalendar и XMLGregorianCalendar очень просто:

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

Но это, похоже, не является ядром вашей проблемы.Вы пытаетесь выполнить преобразование часового пояса?ИМХО, это можно сделать проще, если вы перенесете преобразование на время отображения (поскольку это действительно проблема форматирования), воспользуетесь тем фактом, что и GregorianCalendar, и XMLGregorianCalendar несут с собой информацию о часовом поясе и избавятся от двух вспомогательных классов..

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);
}

Или, возможно, ваша проблема на самом деле заключается в очистке входных данных.Я вижу, что у вас есть переменная вылета и времени, предположительно для рейсов из аэропортов по всему миру, и вы, вероятно, получаете их из какого-либо источника данных, который не имеет явной информации о часовом поясе, а вместо этого предполагает "местное время в аэропорту".Это объяснило бы вспомогательные классы, но в этом случае вы должны очистить свой ввод там, где это происходит.Определить «местное время в аэропорту» иногда бывает сложно (страна может выбрать переход с летнего времени на стандартное через неделю в следующем году или вообще отменить летнее время, а аэропорт, например, может даже переключать часовые пояса в США).перемещение округов с востока на центр и обратно происходит чаще, чем вы думаете).Вы должны использовать базу данных Locale вашего компьютера, чтобы решить эту проблему, и избегать попыток использовать собственную арифметику часовых поясов.

...