Подтвердить что ты не робот

Часовой пояс по умолчанию для десериализации DateTime с помощью Jackson (модуль Joda-Time)

Этот вопрос касается десериализации на Joda-Time DateTime, используя модуль jackson-datatype-joda для Jackson. Существует ли часовой пояс по умолчанию, в котором строки даты будут десериализованы? Если так, то, что это? Это UTC?

Мне нужно спросить об этом, потому что документация Джексона не относится к Joda-Time DateTime. Я нашел в этой статье (http://wiki.fasterxml.com/JacksonFAQDateHandling), что Джексон примет GMT в качестве часового пояса по умолчанию для десериализации в java.util.Date или java.util.Calendar. Однако в этом документе нет упоминаний о типах данных Joda-Time. Кроме того, мне особенно нужны строки для десериализации в объекты DateTime, используя часовой пояс UTC, а не GMT: хотя эти две зоны очень схожи, существуют небольшие различия, и поэтому для меня не будет возможности использовать GMT.

Спасибо.

4b9b3361

Ответ 1

Исходный код DateTimeDeserializer показывает, что он использует часовой пояс из DeserializationContext, который предоставляется ObjectMapper во время десериализации. Если вы посмотрите на ObjectMapper API, вы увидите, что существует способ установки часового пояса:

public ObjectMapper setTimeZone(TimeZone tz)

Таким образом, вы можете использовать этот метод для настройки ObjectMapper и установить правильный часовой пояс.

Что касается значения по умолчанию, кажется, что Javadoc говорит одно, но код показывает другое.

Javadoc для ObjectMapper.setTimeZone(TimeZone tz):

/**
  * Method for overriding default TimeZone to use for formatting.
  * Default value used is {@link TimeZone#getDefault()}.
  */

Однако код явно задает часовой пояс:

protected final static BaseSettings DEFAULT_BASE = new BaseSettings(
    ...
    // TimeZone.getDefault()
    TimeZone.getTimeZone("GMT"),
    ...

Итак, по-видимому, на самом деле он использует GMT, а не по умолчанию по умолчанию JVM.

Я бы сказал, что, вероятно, лучший выбор не будет полагаться на это и установить его самостоятельно на ObjectMapper.setTimeZone(TimeZone tz).

Ответ 2

UTC против GMT

В бизнес-приложениях нет никакой практической разницы между UTC и GMT. Единственное различие относится к второстепенному разрешению, а Leap Second добавляется каждые несколько лет. Для науки, астрономии, спутникового слежения и таких приложений разница может быть значительной, но такая редкая.

Джексон По умолчанию UTC/GMT

Я не знаю Джексона. Но, посмотрев на документ, который вы связали, похоже, что они сериализуют (a) число миллисекунд с 1 января 1970 года, UTC или (b) строковый формат, по умолчанию ISO 8601: "1970-01-01T00: 00: 00.000 + 0000". Итак, чтобы ответить на ваш вопрос о часовых поясах, это похоже на то, что по умолчанию Джексон всегда сериализуется с использованием UTC (без смещения часового пояса), что является правильным способом для этого. Если вам нужен часовой пояс, который использовался в то время, вы должны записать этот факт (какой часовой пояс) в отдельном поле.

Джексон ↔ java.util.Date/Calendar ↔ Joda-Time

Оба этих сериализованных значения (миллисекунды и строка ISO 8601) могут использоваться с конструкторами для экземпляров Joda-Time DateTime.

String dateTimeString = "2013-11-22T18:37:55.645+0000";
org.joda.time.DateTime myDateTime = org.joda.time.format.ISODateTimeFormat.dateTime().withZoneUTC().parseDateTime( dateTimeString );

и...

Long millisSinceEpoch = 1385495462L;
org.joda.time.DateTime myDateTime = new org.joda.time.DateTime( millisSinceEpoch );

Если у вас нет прямого доступа к этим сериализованным значениям для подачи на конструкторы Joda-Time DateTime, тогда пусть Джексон создаст объекты java.util.Date/Calendar. Загрузите те объекты java.util.Date/Calendar в Joda-Time, чтобы создать объекты DateTime для дальнейшей работы. Пользователи Joda-Time обычно это делают.

org.joda.time.DateTime myDateTime = new org.joda.time.DateTime( someJavaUtilDateFromJackson );

Вы можете легко преобразовать это время UTC в другие часовые пояса в Joda-Time, вызвав метод toDateTime() и передав требуемый часовой пояс.

org.joda.time.DateTimeZone kolkataTimeZone = org.joda.time.DateTimeZone.forID( "Asia/Kolkata" );
org.joda.time.DateTime dateTimeInKolkata = myDateTime.toDateTime( kolkataTimeZone ); 

Joda-Time легко конвертирует обратно в java.util.Date, используя метод toDate. Так что делайте большую часть своей работы в Joda-Time и конвертируйте обратно в java.util.Date, чтобы общаться с Джексоном. И, возвращаясь к Джексону, я бы переключил свои DateTimes на UTC только для хорошей меры.

myDateTime.toDateTime( org.joda.time.DateTimeZone.UTC )

Вы найдете много примеров вышеупомянутых операций Joda-Time здесь, на StackOverflow.com.

Просто сделай это

Я подозреваю, что вы слишком много беспокоитесь и недостаточно кодируете. Просто попробуйте несколько небольших экспериментов, передающих ценности в и из Джексона и Йода-Времени. Вы быстро это почувствуете. Я рекомендую вам позволить Джексону делать то, что он хочет сделать по умолчанию, а затем манипулировать в Joda-Time. Joda-Time построена для суровых проблем даты-времени, а Джексона, по-видимому, нет. Joda-Time имеет как конструкторы, так и методы для настройки между часовыми поясами по желанию.

Яркое будущее

В Java 8, JSR 310: API дат и времени добавлены классы Joda-Time, встроенные в платформу Java. Ожидайте увидеть, как фреймворки, такие как Jackson, обновлены, чтобы напрямую работать с этими новыми классами, в то же время игнорируя уродливые классы java.util.Date/Calendar.

Похоже, что проект jackson-datatype-joda пытается принести вам такое удобство для Joda-Time. Но мне это не кажется нужным. Вы можете просто конвертировать между java.util.Date/Calendar и Joda-Time, как описано выше.

P.S. Ссылка "Wiki" для этой проектной документации не удалась. Поэтому я не мог смотреть на их документ.

Ответ 3

Из простого кода я обнаружил, что когда Джексон десериализует объект Date из строки, он дает UTC, если не упоминается часовой пояс, но когда он создается непосредственно, дает часовой пояс по умолчанию т.е. часовой пояс машины.

DateTime date = new DateTime(2013, 1, 2, 0, 0) //gives local timezone

Ниже приводится UTC

ObjectMapper mapper = new ObjectMapper();
DateTime dt = new DateTime(2013, 1, 2, 0, 0);
String serialized = mapper.writeValueAsString(dt);
DateTime dt1 = mapper.readValue(serialized, DateTime.class); //gives UTC

Ответ 4

Я также боролся с форматами дат и, наконец, нашел решение. Я хотел использовать формат "2016-02-08T12:49:22.876Z", так как это ISO 8601, и он используется JavaScript Date. Я также хотел всегда использовать часовой пояс UTC.

Я обнаружил, что это можно сделать с помощью следующего кода:

final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(dateFormat);

System.out.println(objectMapper.writeValueAsString(new Date()));

Обратите внимание на символ X в строке формата. Он поддерживается Java 7 и указывает часовой пояс в ISO 8601. Как описано в SimpleDateFormat, он производит Z (вместо +00:00), если смещение часового пояса равно 0 (UTC).