Часова зона на Java при разбор на DateFormat

Имах код, който анализира датата, както следва:

String ALT_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
SimpleDateFormat sdf = new SimpleDateFormat(
                    ALT_DATE_TIME_FORMAT);
Date date = sdf.parse(requiredTimeStamp);

И работеше добре, изведнъж това спря да работи. Оказва се, че администраторът е направил някои промени в конфигурацията на сървъра и в момента датата се връща като "2010-12-27T10:50:44.000-08:00", което не може да се анализира от горния модел. Имам два въпроса:

Първият ще бъде какъв модел ще анализира датата, върната от JVM във формата по-горе (по-конкретно, само '-08:00' като часова зона)? И второ, къде точно бихме променили такива настройки на linux RHEL 5 сървър, така че да сме наясно с подобни промени в бъдеще?


person shipmaster    schedule 27.12.2010    source източник


Отговори (8)


Другото приложение използва формат ISO 8601 dateTime. Предполагам, че другото приложение ви изпраща XML отговор, който е в съответствие с типа dateTime на XML схемата, който е ISO 8601. Вече е известно, че DateFormat не може да анализира този формат. Или трябва да използвате други библиотеки като joda-time (joda-time е победителят) или FastDateFormat, както е посочено в другите отговори. Вижте тази публикация Конвертиране на ISO 8601-съвместим низ в java.util.Date

person Aravind Yarram    schedule 28.12.2010
comment
Библиотеката Joda-Time работи, но сега е в режим на поддръжка. Екипът съветва миграция към класовете java.time. - person Basil Bourque; 06.09.2016

tl;dr

OffsetDateTime.parse( "2010-12-27T10:50:44.000-08:00" )

ISO 8601

Форматът на входния низ е дефиниран в стандарта ISO 8601, семейство формати за дата-час.

Избягвайте стари класове за дата-час

Въпросът и другите отговори използват стари остарели класове за дата-час, свързани с най-ранните версии на Java. Избягвайте ги. Сега изместен от класовете java.time.

Използване на java.time

Вашият въведен низ завършва с offset-from-UTC. Така че анализираме като OffsetDateTime обект.

Класовете java.time използват формати ISO 8601 по подразбиране при анализиране/генериране на низове. Така че няма нужда да указвате шаблон за форматиране.

OffsetDateTime odt = OffsetDateTime.parse( "2010-12-27T10:50:44.000-08:00" );

Ако искате да видите тази стойност за дата-час като момент на времевата линия в UTC, извлечете Instant.

Instant instant = odt.toInstant();

Часовата зона е отместване плюс набор от правила за справяне с аномалии като лятно часово време (DST). Ако имате предвид часова зона, приложете ZoneId, за да получите ZonedDateTime обект. Същият момент на времевата линия, но гледан през различно време на стенния часовник.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );  // Same moment on the timeline, but viewed through a different wall-clock time.


Относно java.time

java.time рамката е вградена в Java 8 и по-нови версии. Тези класове изместват проблемните стари наследени класове за дата-час като java.util.Date, Calendar, & SimpleDateFormat.

Проектът Joda-Time, сега в режим на поддръжка, съветва миграция към java.time класове.

За да научите повече, вижте урока за Oracle . И потърсете в Stack Overflow много примери и обяснения. Спецификацията е JSR 310.

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

Къде да получа класовете java.time?

  • Java SE 8, Java SE 9, and later
    • Built-in.
    • Част от стандартния Java API с пакетна реализация.
    • Java 9 добавя някои незначителни функции и поправки.
  • Java SE 6 and Java SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android

Проектът ThreeTen-Extra разширява java.time с допълнителни класове. Този проект е тестова площадка за възможни бъдещи допълнения към java.time. Тук може да намерите някои полезни класове като Interval, YearWeek, YearQuarter и още.

person Basil Bourque    schedule 05.09.2016

Ако искате да го анализирате чрез прав JDK, вярвам, че трябва да може да се анализира с помощта на JAXB utils, вижте DatatypeFactory.newXMLGregorianCalendar или DatatypeConverter.parseDateTime.

person jtahlborn    schedule 28.12.2010

Използвайте JodaTime

Като по-конкретен пример за предложението на @Pangea да използвате JodaTime, можете да използвате това:

String timestamp = "2012-09-17T04:11:46Z";

DateTime date = ISODateTimeFormat.dateTimeParser().parseDateTime(timestamp);

Това правилно разпознава часовата зона UTC. Не съм го пробвал с милисекунди в времевия знак на низа, но съм уверен, че ще работи също толкова добре.

Надявам се това да помогне на другите.

JP

person Joshua Pinter    schedule 10.12.2013
comment
FYI: Проектът Joda-Time, сега в режим на поддръжка, съветва мигриране към java.time класове. - person Basil Bourque; 29.12.2016
comment
@BasilBourque Благодаря, че посочи това! Ако използвате Java SE 8+, те препоръчват преминаване към java.time. Щастлив съм да видя, че тези подобрения се въвеждат в ядрото. - person Joshua Pinter; 02.01.2017
comment
Голяма част от функционалността на java.time е обратно пренесена към Java 6 и 7 в ThreeTen-Backport. Допълнително адаптиран за Android в проекта ThreeTenABP. - person Basil Bourque; 02.01.2017
comment
За информация, всички тези проекти (Joda-Time, JSR 310, java.time класове, ThreeTen-Backport и ThreeTen-Extra) се ръководят от един и същи човек, Стивън Колбърн. - person Basil Bourque; 05.07.2018

Въпросът трябва да бъде откъде идва requiredTimeStamp и в какъв формат. Въведен ли е от потребител или е прочетен от друга програма? Кой компонент създава датата в представянето на низ?

Форматът "2010-12-27T10:50:44.000-08:00" изглежда като стандартизиран формат ISO-8601 Трябва да може да се анализира с модела yyyy-MM-dd'T'HH:mm:ss.SSSZ

Не съм сигурен кои настройки засягат това, но има ЧЗВ на Oracle за Java Часови зони. Може да е user.timezone системно свойство или /etc/localtime символна връзка в RHEL.

person mhaller    schedule 28.12.2010
comment
Съжалявам, че не бях ясен. requiredTimeStamp се генерира от java приложение на сървъра (не нашия) и се изпраща като част от отговор на услугата. Изглежда, че използва някои настройки на сървъра по подразбиране, тъй като се променя с преконфигуриране на сървъра. Часовото клеймо „-08:00“ не може да се анализира от Z в шаблона дори в изолиран модулен тест на моята машина, Z може да анализира „-0800“ или „GMT-08:00“, но не и „-08:00 '. - person shipmaster; 28.12.2010

SimpleDateFormat приема само -0800 или GMT-08:00 като часова зона.

Изглежда форматът ISO 8601 не може да бъде анализиран с SimpleDateFormat. Може би трябва да погледнете Apache Commons Lang .apache.org/lang/api-release/org/apache/commons/lang/time/FastDateFormat.html" rel="nofollow">FastDateFormat. Той е съвместим с SimpleDateFormat, но приема модела ZZ за часовата зона, която трябва да анализира формата на часовата зона, от който се нуждаете. DateFormatUtils съдържа някои примерни константи които изглеждат като шаблона, от който се нуждаете, само без милисекунди (например ISO_DATETIME_TIME_ZONE_FORMAT).

person Reboot    schedule 28.12.2010
comment
Доколкото разбрах, FastDateFormat не поддържа синтактичен анализ. - person shipmaster; 28.12.2010
comment
Изглежда си прав. Тъй като прилага стандартния интерфейс за форматиране, предположих, че той също ще анализира формата като SimpleDateFormat. Не проверих коментарите за методите за анализ. - person Reboot; 29.12.2010

Опитайте да го промените на малки z.

z обработва повечето от общия общ синтаксис на часовата зона, докато Z използва по-строга RFC 822 часова зона с 4 цифри.

Въпреки че е документирано, че и двете трябва да анализират „Общи настройки на часовата зона“, това може да направи разликата във вашия случай.

person jbx    schedule 28.12.2010

ако все още търся отговор, това работи за мен

Моят вход: 2020-12-08T10:36:53.939+05:30
Моят резултат: Tue Dec 08, 10:36:53 IST 2020

Можете да конвертирате тази дата във всеки формат, от който се нуждаете!

private static Date convertDate(String input) {
    Date newDate = null;
    try {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
        newDate=dateFormat.parse(input);  
    } catch (Exception e) {
        e.printStackTrace();
    }
    return newDate;
}
person Srikanth Josyula    schedule 08.12.2020