Разбор даты с Йодой с часовым поясом - PullRequest
14 голосов
/ 07 января 2011

У меня есть две метки времени, которые описывают один и тот же момент времени в двух разных форматах.

2010-10-03 18:58:07 и 2010-10-03T16:58:07.000+02:00.

Я анализирую метки времени с двумя разными форматерами даты с помощью Joda-Время.В конце я хочу получить два объекта DateTime, которые равны с точки зрения одинакового момента времени.

DateFormatter предлагает несколько методов для управления часовыми поясами и локалями, но я не могу заставить его работать.

Это код, с которым я хотел бы работать:

    final String date1 = "2010-10-03 18:58:07"; // Europe/Berlin local time
    final DateTimeFormatter formatter1 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
    final DateTime dateTime1 = formatter1.parseDateTime(date1);

    final String date2 = "2010-10-03T16:58:07.000+02:00"; // Europe/Berlin local time with time zone
    final DateTimeFormatter formatter2 = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    final DateTime dateTime2 = formatter2.parseDateTime(date2);

    Assert.assertTrue(dateTime1.isEqual(dateTime2));

Ответы [ 4 ]

7 голосов
/ 07 января 2011

Если по умолчанию установлено значение zome Европа / Берлин, 2010-10-03 18:58:07 соответствует 2010-10-03T16: 58: 07.000 + 00: 00.

Возможно, вы неправильно понимаете поле часового пояса в строковом представлении. Ваша отметка времени 2010-10-03T16: 58: 07.000 + 02: 00 означает, что «это 16:58:07 в часовом поясе со смещением +2 часа от GMT) или в другой формулировке» теперь оно равно : 58: 07 в Берлине ". Полагаю, вы ожидали, что это будет означать, что сейчас 16:58:07 по Гринвичу?

4 голосов
/ 07 января 2011

Ваши две метки времени не представляют один и тот же момент времени (как уже отмечал jambjo).См. Часовой пояс как смещения от UTC в Википедии.

Также смотрите документацию parseDateTime о том, как это работает.Если вы не укажете часовой пояс, будет применен часовой пояс по умолчанию (т. Е. Часовой пояс Берлина UTC + 2, если вы там).Итак:

  • 2010-10-03 18:58:07 становится 2010-10-03T18:58:07.000+02:00 (18:58 в Берлине со смещением на 2 часа по UTC, что означает 16:58 в UTC), как и ожидалось.
  • 2010-10-03T16:58:07.000+02:00 остается без изменений, поскольку предоставлен часовой пояс (т. Е. 16:58 в Берлине со смещением на 2 часа по UTC, что означает 14:58 в UTC)

Надеюсь, вы получилиидея.Вам нужно будет скорректировать время с помощью метода withZone , чтобы получить желаемые результаты.

1 голос
/ 26 октября 2018

tl; dr

Используйте современные java.time классы, которые вытеснили Joda-Time .

LocalDateTime                                   // Represent a date and time-of-day without the context of a time zone or offset-from-UTC. *Not* a moment, *not* a point on the timeline.
.parse(                                         // Parse text into a date-time value.
    "2010-10-03 18:58:07".replace( " " , "T" )  // Replace SPACE in middle with a `T` to comply with ISO 8601 standard used by default in *java.time* when parsing/generating strings.
)                                               // Returns a `LocalDateTime` object.
.atZone(                                        // Assign the time zone we know for certain was intended for this input. 
    ZoneId.of( "Europe/Moscow" )                // Real time zones are named in `Continent/Region` format, never 2-4 letter codes such as CST, PST, IST, CEST, etc.
)                                               // Returns a `ZonedDateTime` object, a date with time-of-day and with a time zone assigned to determine a moment.
.toInstant()                                    // Adjust from time zone to UTC. 
.equals(
    OffsetDateTime                              // Represent a date and time-of-day with an offset-from-UTC but not a full time zone.
    .parse( "2010-10-03T16:58:07.000+02:00" )   // Parse a standard ISO 8601 string.
    .toInstant()                                // Adjust from offset to UTC (in other words, an offset of zero hours-minutes-seconds). 
)                                               // Returns `boolean`. 

true

Подробности

Ответ от jarnbjo является правильным в том смысле, что вы неправильно поняли значения смещение от UTC и значения часового пояса .

Сейчас в 2018 году проект Joda-Time находится вРежим технического обслуживания.Основной автор этого проекта, Стивен Коулборн, основал JSR 310 и создал его реализацию, java.time классы, найденные в OpenJDK .

Первый ввод

Ваша строка ввода 2010-10-03 18:58:07 почти в стандартном формате ISO 8601 .Для соответствия замените ПРОБЕЛ в середине на T.

String input1 = "2010-10-03 18:58:07".replace( " " , "T" ) ;

В этой строке отсутствует индикатор часового пояса или смещения от UTC.Так что LocalDateTime.

LocalDateTime ldt = LocalDateTime.parse( input1 ) ;

Это значение не представляет момент, является не точкой на временной шкале.Без контекста зоны или смещения это может быть любой из множества моментов в диапазоне около 26-27 часов, в диапазоне часовых поясов по всему земному шару.

В ваших комментариях вы указали, что очевидно, что входная строка предназначена для представления даты и времени суток в часовом поясе Europe/Moscow.Таким образом, мы можем назначить эту зону для определения момента, точки на временной шкале.

ZoneId zMoscow = ZoneId.of( "Europe/Moscow" ) ;
ZonedDateTime zdtMoscow = ldt.atZone( zMoscow ) ;  // Determine a moment by assigning a time zone.

zdtMoscow.toString (): 2010-10-03T18: 58: 07 + 04: 00 [Европа/ Москва]

Второй вход

Ваш второй вход 2010-10-03T16:58:07.000+02:00 соответствует стандартному формату ISO 8601 .

Этот вход содержит смещение от UTC на два часа впереди UTC.Таким образом, эта строка представляет время суток 14:58:07 в UTC.

Мы можем проанализировать как OffsetDateTime для соблюдения заданного смещения.

OffsetDateTime odt2 = OffsetDateTime.parse( "2010-10-03T16:58:07.000+02:00" ) ;

odt2.toString (): 2010-10-03T16: 58: 07 + 02:00

Сравнить

Эти два входа представляют один и тот же момент, одну и ту же точку на временной шкале?

Один из способов сравнения - настроить оба значения на UTC.Instant всегда в UTC, по определению.

Совет: приобретите привычку думать, работать, хранить, обмениваться и регистрироваться в UTC.Представьте себе UTC как Единственное истинное время .

Instant instant1 = zdtMoscow.toInstant() ;  // Adjust from time zone to UTC.
Instant instant2 = odt2.toInstant() ;       // Adjust from offset to UTC.

boolean equality = instant1.equals( instant2 );

При запуске мы видим результаты с Z в конце.Это означает UTC и произносится как Zulu.И действительно, мы видим, что эти два значения представляют один и тот же момент, почти 3 часа дня в UTC.

instant1.toString (): 2010-10-03T14: 58: 07Z

instant2.toString (): 2010-10-03T14: 58: 07Z

равенство: true


О java.time

Рамка java.time встроенный в Java 8 и позже.Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar и & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .

Вы можете обмениваться java.time объектами напрямую с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 , Java SE 10, Java SE 11 и более поздние версии - часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и JavaSE 7
    • Большинство функций java.time перенесено в Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии Android связывают реализации классов java.time .
    • Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .

ThreeTen-Extra Проект расширяет java.time дополнительными классами.Этот проект является полигоном для возможных будущих дополнений к java.time.Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и more .

0 голосов
/ 25 октября 2018

У меня была та же проблема, что и у вас, и лучший способ, который я нашел, - это проанализировать данные.Первоначально у меня был такой формат: 2018-01-22 09: 25: 14.000 + 0000

Просто выберите столбец и нажмите «Текст в столбцы» на вкладке «Данные».

Я использовал разделитель сместо для разбора этого формата в 3 разных столбцах.Итак, в конце у меня есть:

Col A 2018-01-22 Col B 09: 25: 14.000 Col C + 0000

...