Java Дата и время удаляют часовой пояс с указанной даты «2019-12-03T10: 00: 00-06: 00», а ожидаемая дата «2019-12-03T10: 00: 00» - PullRequest
0 голосов
/ 21 января 2020
LocalDateTime formatOrderEndDateTime;
    try {
        DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
        formatOrderEndDateTime = LocalDateTime.parse("2019-12-03T10:00:01+01:00", formatter);
        System.out.println(formatOrderEndDateTime);
    } catch (Exception e) {
        throw new IllegalArgumentException();
    }

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

заданная дата ввода: 2019-12-03T10: 00: 00-06: 00 или 2019-12-03T10: 00: 00

ожидаемая дата о / п: 2019-12-03T10 : 00: 00

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

Ответы [ 3 ]

3 голосов
/ 21 января 2020

Момент

заданная дата ввода: 2019-12-03T10: 00: 00-06: 00 или 2019-12-03T10: 00: 00

Те два очень разных животных.

Первый представляет момент, определенный c пункт на временной шкале. Второго нет. Второй - 10:00 в Токио, 10:00 в Тулузе или 10:00 в Толедо - три совершенно разных момента с разницей в несколько часов.

Первый должен быть разобран как OffsetDateTime. Второй должен быть разобран как LocalDateTime.

Неверный тип

Для ввода, такого как 2019-12-03T10:00:00-06:00, проанализировать как OffsetDateTime. Вы использовали LocalDateTime, который не может обработать смещение от UT C в конце этой строки.

Нет необходимости указывать шаблон форматирования. Ваш ввод соответствует стандарту ISO 8601, используемому по умолчанию.

OffsetDateTime odt = OffsetDateTime.parse( "2019-12-03T10:00:00-06:00" )

Неправильный форматер

Чтобы сгенерировать текст в формате ISO 8601, в котором пропущено смещение, используйте DateTimeFormatter.ISO_LOCAL_DATE_TIME.

String output = odt.format( DateTimeFormatter.ISO_LOCAL_DATE_TIME ) ;

Смещение относительно часового пояса

не работает, если часовой пояс

Ваши входы не имеют часового пояса. Они имеют смещение от UT C. Смещение - это просто количество часов, минут и секунд.

Часовой пояс намного больше. Часовой пояс - это история прошлых, настоящих и будущих изменений смещения, используемых людьми определенного региона. Часовой пояс имеет имя в форме Continent/Region, например Europe/Paris.

1 голос
/ 21 января 2020

Вы не должны хотеть LocalDateTime

Например: две строки 2019-12-03T10:00:01+09:00 и 2019-12-03T10:00:01-08:00 обозначают точки во времени с интервалом в 17 часов, но будут разбиты на равные LocalDateTime объекты. Я не думаю, что вы хотите этого.

Также LocalDateTime, вероятно, не подходит для времени окончания заказа. Он не знает никакого часового пояса или смещения от UT C, поэтому каждый человек и каждый фрагмент кода, увидевший его, будут иметь возможность свободно интерпретировать часовой пояс, о котором они думают, а не предполагаемый. Это оставляет большой риск непредвиденных результатов. По крайней мере для 19 из 20 целей вам будет лучше использовать Instant, OffsetDateTime или ZonedDateTime.

Разбор со смещением и без него: определите часовой пояс по умолчанию

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

Например:

    ZoneId defaultTimeZone = ZoneId.of("America/Guatemala");
    ZoneId resultTimeZone = ZoneId.of("Europe/Rome");
    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
            .appendPattern("[XXX]")
            .toFormatter();


    for (String input : new String[] {
            "2019-12-03T10:00:01+01:00",
            "2019-12-03T10:00:00-06:00",
            "2019-12-03T10:00:00"
    }) {
        TemporalAccessor parsed = formatter.parseBest(input,
                OffsetDateTime::from, LocalDateTime::from);
        ZonedDateTime dateTime;
        if (parsed instanceof OffsetDateTime) {
            dateTime = ((OffsetDateTime) parsed).atZoneSameInstant(resultTimeZone);
        } else {
            dateTime = ((LocalDateTime) parsed).atZone(defaultTimeZone)
                    .withZoneSameInstant(resultTimeZone);
        }
        System.out.format("%-25s is parsed into %s%n", input, dateTime);
    }

Вывод этого фрагмента:

2019-12-03T10:00:01+01:00 is parsed into 2019-12-03T10:00:01+01:00[Europe/Rome]
2019-12-03T10:00:00-06:00 is parsed into 2019-12-03T17:00+01:00[Europe/Rome]
2019-12-03T10:00:00       is parsed into 2019-12-03T17:00+01:00[Europe/Rome]

Я использую [XXX] в строке шаблона формата для обозначения необязательного смещения. Вызов parseBest() анализируется в OffsetDateTime, если это возможно (смещение присутствует), в противном случае в LocalDateTime, который я впоследствии конвертирую. Наконец, я конвертирую все проанализированные даты и время в один часовой пояс, чтобы пользователь мог видеть согласованные результаты.

1 голос
/ 21 января 2020

Я думаю, вам придется использовать другую пару форматеров, как показано в коде ниже. Из документации DateTimeFormatter.ISO_DATE_TIME:

ISO-подобный форматер даты и времени, который форматирует или анализирует дату-время со смещением и зоной, если доступно, например, '2011-12-03T10: 15 : 30 ',' 2011-12-03T10: 15: 30 + 01: 00 'или' 2011-12-03T10: 15: 30 + 01: 00 [Европа / Париж] '.

Тогда вам придется использовать другой форматер для преобразования его в строку вместо использования LocalDateTime.toString().

LocalDateTime formatOrderEndDateTime;
try {
     DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
     formatOrderEndDateTime = LocalDateTime.parse(line.trim(), formatter);

     DateTimeFormatter f2 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
     System.out.println(formatOrderEndDateTime.format( f2 ));
} catch (Exception e) {
     System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}

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

...