DateTimeFormatter принимает несколько типов и преобразует их в один

Я пытаюсь написать DateTimeFormatter, который позволит мне использовать несколько разных форматов строк, а затем преобразовывать форматы строк в определенный тип. Из-за масштаба проекта и уже существующего кода я не могу использовать форматтер другого типа.

например. Я хочу принять MM/dd/yyyy, а также yyyy-MM-dd'T'HH:mm:ss, но затем преобразовать их в MM/dd/yyyy.

Может ли кто-нибудь предложить идеи о том, как это сделать с org.joda.time.format?

Я не нашел хороший/рабочий пример этого онлайн.


person Alex Kornhauser    schedule 14.06.2017    source источник
comment
Я не уверен, в чем разница, но я хочу преобразовать строку в DateTime, т.е. DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(MM/dd/yyyy);   -  person Alex Kornhauser    schedule 14.06.2017


Ответы (1)


Я использую Joda-Time 2.9.7 и JDK 1.7.0_79.

Вы можете использовать DateTimeFormatterBuilder.append метод: он получает принтер (с шаблоном, используемым для печати даты/времени) и массив парсеров со всеми возможными входными шаблонами :

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import org.joda.time.format.DateTimeParser;

// MM/dd/yyyy format
DateTimeFormatter monthDayYear = DateTimeFormat.forPattern("MM/dd/yyyy");
// array of parsers, with all possible input patterns
DateTimeParser[] parsers = {
    // parser for MM/dd/yyyy format
    monthDayYear.getParser(),
    // parser for yyyy-MM-dd'T'HH:mm:ss format
    DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss").getParser() };
DateTimeFormatter parser = new DateTimeFormatterBuilder()
    // use the monthDayYear formatter for output (monthDayYear.getPrinter()) and parsers array for input (parsers)
    .append(monthDayYear.getPrinter(), parsers)
    // create formatter (using UTC to avoid DST problems)
    .toFormatter().withZone(DateTimeZone.UTC);

// test with MM/dd/yyyy
DateTime datetime1 = parser.parseDateTime("06/14/2017");
System.out.println(parser.print(datetime1)); // 06/14/2017

// test with yyyy-MM-dd'T'HH:mm:ss
DateTime datetime2 = parser.parseDateTime("2017-06-14T10:30:40");
System.out.println(parser.print(datetime2)); // 06/14/2017

Я использовал DateTimeZone.UTC, чтобы избежать проблем с переходом на летнее время.

Например, в моем часовом поясе по умолчанию (America/Sao_Paulo) в прошлом году (2016) переход на летнее время начался 16 октябряth: в полночь часы переводятся на 1 час вперед (так что технически, полночи в этот день не существует, потому что время меняется с 23:59:59 на 01:00:00).

Проблема в том, что при синтаксическом анализе формата MM/dd/yyyy нет полей для часа, минуты или секунды, и анализатор устанавливает 0 в качестве значения по умолчанию для всех этих полей (поэтому час становится полночью). Но если я попытаюсь проанализировать дату начала летнего времени (например, 10/16/2016) и не использовать UTC, как указано выше, код выдаст исключение, потому что в этот день полночи не существует (из-за часового сдвига летнего времени).

Использование UTC позволяет избежать этой ошибки, так как DateTimeZone.UTC не влияет на переход на летнее время. При этом код работает независимо от часового пояса вашей системы по умолчанию.

Результат:

06/14/2017
06/14/2017


PS: Поскольку вас интересует только часть даты (день/месяц/год), вы также можете использовать класс org.joda.time.LocalDate. Чтобы использовать его, просто измените последнюю часть кода (можно использовать тот же parser):

// test with MM/dd/yyyy
LocalDate dt1 = parser.parseLocalDate("06/14/2017");
System.out.println(parser.print(dt1)); // 06/14/2017

// test with yyyy-MM-dd'T'HH:mm:ss
LocalDate dt2 = parser.parseLocalDate("2017-06-14T10:30:40");
System.out.println(parser.print(dt2)); // 06/14/2017

Вывод тот же:

06/14/2017
06/14/2017

Использование LocalDate — еще один способ избежать проблем с переходом на летнее время (как объяснялось выше). В этом случае вам не нужно устанавливать UTC, потому что LocalDate не имеет информации о часовом поясе.

person Community    schedule 14.06.2017
comment
@AlexKornhauser Я обновил ответ: проведя несколько тестов, я обнаружил некоторые потенциальные ошибки с летним временем, поэтому я соответствующим образом исправил код. - person ; 14.06.2017
comment
Как бы я сделал то же самое с библиотекой java.time, например, DateTimeFormatter.ofPattern(MM/dd/yyyy); + DateTimeFormatter.ofPattern(yyyy-MM-dd'T'HH:mm:ss); - person Alex Kornhauser; 17.06.2017
comment
Я не думаю, что в новом API есть такая функция, возможно, вам понадобится один модуль форматирования для анализа ввода (используйте необязательный шаблон [MM/dd/yyyy][yyyy-MM-dd'T'HH:mm:ss]), а другой - для форматирования вывода. - person ; 17.06.2017