java.time шаблон DateTimeFormatter для смещения часового пояса

Я пытаюсь разобрать: 2014-05-02-10.45.05.993280-5:00, где -5:00 - это смещение от UTC. Использование DateTimeFormatter в java.time Java 8.

Для первого бита у меня есть следующее: yyyy-MM-dd-HH.mm.ss.SSSSSS однако я не могу понять, каким должен быть шаблон для анализа смещения.

Если бы у меня было смещение с 4 цифрами (-05: 00), я мог бы использовать: yyyy-MM-dd-HH.mm.ss.SSSSSSxxx, но это не работает для 3 цифр.

Любые идеи?


person Cheetah    schedule 08.06.2015    source источник


Ответы (3)


Используйте заглавную букву X вместо x, следовательно, XXX. Разница в том, что большая буква X может распознать входную букву Z как UTC-Offset +00: 00, а маленькая буква X не может.

Предлагаемый шаблон:

yyyy-MM-dd-HH.mm.ss.SSSSSSXXX

Также помните о следующей ошибке JDK:

java.time.format.DateTimeFormatter не может анализировать смещение с однозначным часом

ОБНОВЛЕНИЕ:

Я проверил описанный обходной путь в журнале ошибок.

String input = "2014-05-02-10.45.05.993280-5:00";
DateTimeFormatter f = new DateTimeFormatterBuilder()
        .appendPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS")
        .parseLenient()
        .appendOffset("+HH:MM", "Z")
        .toFormatter();
System.out.println(f.parse(input, ZonedDateTime::from));

Но возникает исключение:

Исключение в основном потоке java.time.format.DateTimeParseException: текст '2014-05-02-10.45.05.993280-5: 00' не удалось проанализировать в индексе 26 в java.time.format.DateTimeFormatter.parseResolved0 (DateTimeFormatter.java: 1947) в java.time.format.DateTimeFormatter.parse (DateTimeFormatter.java:1849) в HelloWorld.main (HelloWorld.java:16)

Так что мягкий разбор тоже не помогает. Итак, теперь вам осталось только три варианта:

  • Используйте обходной путь, предложенный репортером: [...] обходной путь состоит в том, чтобы проанализировать дату / время отдельно, использовать кодированный вручную синтаксический анализатор для смещения и объединить LocalDateTime с вручную проанализированным смещением. Непростой обходной путь.

  • Попробуйте свою собственную специализированную предварительную обработку строк. Если у вас фиксированный формат, вы можете попытаться вставить нулевую цифру в позицию 26 (если общая длина ввода слишком мала на одну цифру).

  • Или вы используете внешнюю библиотеку, которая может это сделать. Моя библиотека Time4J (v4.0) может это сделать, если вы хотите добавить дополнительную зависимость. Смотрите этот код:

String input = "2014-05-02-10.45.05.993280-5:00";
ZonalDateTime zdt =
    ZonalDateTime.parse(
        input,
        Moment.localFormatter("yyyy-MM-dd-HH.mm.ss.SSSSSSXXX", PatternType.CLDR));
System.out.println(zdt); // 2014-05-02T10:45:05,993280UTC-05:00
ZonedDateTime result = zdt.toTemporalAccessor();

Обновление. Согласно JDK-bug-status, ошибка была исправлена ​​для Java-9, но обратный порт для Java-8, похоже, недоступен.

person Meno Hochschild    schedule 08.06.2015
comment
Шаблон не работает ... но ссылка на ошибку выглядит как моя проблема. Я попробовал предложение строителя, но оно тоже не сработало. - person Cheetah; 08.06.2015
comment
@Cheetah Вы правы. Извините, что у вас возникла ошибка. См. Также мое обновление, если вы можете использовать какие-либо альтернативные решения. - person Meno Hochschild; 08.06.2015

Смещение для знака SimpleDateFormat: Z отметьте Java7 или Java8 SimpleDateFormat API .

Затем ваш формат парсера для String

2014-05-02-10.45.05.993280-5:00

должно быть:

yyyy-MM-dd-HH.mm.ss.SSSSSSZ

ОБНОВЛЕНИЕ: для DateTimeFormatter смещение Шаблоны для форматирования и анализа:

O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
Z       zone-offset                 offset-Z          +0000; -0800; -08:00;

Ваш желаемый узор в DateTimeFormatter - X.

person Jordi Castilla    schedule 08.06.2015
comment
Я использую DateTimeFormatter, и добавление Z не работает - person Cheetah; 08.06.2015
comment
Вы дважды связались с Java 7. API Java 8 уже здесь. - person dcsohl; 08.06.2015
comment
Я пробовал варианты этого и не могу заставить его печатать формат +00: 00 по времени GMT. Он будет печатать только +0000. С другой стороны, если часовой пояс смещен как минимум на 1, DateTimeFormatter.ISO_OFFSET_DATE_TIME напечатает прежний желаемый шаблон. - person djangofan; 07.04.2018

Все ответы хороши. В java8 + есть следующие шаблоны для синтаксического анализа и форматирования часового пояса: V, z, O, X, x, Z.

Вот они, для разбора, согласно правилам из документации:

   Symbol  Meaning                     Presentation      Examples
   ------  -------                     ------------      -------
   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
   z       time-zone name              zone-name         Pacific Standard Time; PST
   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;

Но как насчет форматирования? Вот образец даты (при условии ZonedDateTime), демонстрирующий поведение этих шаблонов для разных шаблонов форматирования:

// The helper function:
static void printInPattern(ZonedDateTime dt, String pattern) {
    System.out.println(pattern + ": " + dt.format(DateTimeFormatter.ofPattern(pattern)));
}        

// The date:
String strDate = "2020-11-03 16:40:44 America/Los_Angeles";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss zzzz");
ZonedDateTime dt = ZonedDateTime.parse(strDate, format);
// 2020-11-03T16:40:44-08:00[America/Los_Angeles]

// Rules:
// printInPattern(dt, "V");     // exception!
printInPattern(dt, "VV");       // America/Los_Angeles
// printInPattern(dt, "VVV");   // exception!
// printInPattern(dt, "VVVV");  // exception!
printInPattern(dt, "z");        // PST
printInPattern(dt, "zz");       // PST
printInPattern(dt, "zzz");      // PST
printInPattern(dt, "zzzz");     // Pacific Standard Time
printInPattern(dt, "O");        // GMT-8
// printInPattern(dt, "OO");    // exception!
// printInPattern(dt, "OO0");   // exception!
printInPattern(dt, "OOOO");     // GMT-08:00
printInPattern(dt, "X");        // -08
printInPattern(dt, "XX");       // -0800
printInPattern(dt, "XXX");      // -08:00
printInPattern(dt, "XXXX");     // -0800
printInPattern(dt, "XXXXX");    // -08:00
printInPattern(dt, "x");        // -08
printInPattern(dt, "xx");       // -0800
printInPattern(dt, "xxx");      // -08:00
printInPattern(dt, "xxxx");     // -0800
printInPattern(dt, "xxxxx");    // -08:00
printInPattern(dt, "Z");        // -0800
printInPattern(dt, "ZZ");       // -0800
printInPattern(dt, "ZZZ");      // -0800
printInPattern(dt, "ZZZZ");     // GMT-08:00
printInPattern(dt, "ZZZZZ");    // -08:00

В случае положительного смещения знак + используется везде (где сейчас -) и никогда не опускается.

Это хорошо работает для новых типов java.time. Если вы собираетесь использовать их для java.util.Date или java.util.Calendar - не все будут работать, поскольку эти типы не работают (и поэтому помечены как устаревшие, пожалуйста, не используйте их)

person msangel    schedule 01.02.2021
comment
ФОРМАТИРОВАНИЕ символа - вот что вызывало у меня проблемы. Спасибо за подробный пример! - person SnellyBigoda; 30.04.2021