ZonedDateTime не отображает часовой пояс, ожидаемый через DateTimeFormatter

У меня есть ввод даты с часовым поясом EST.

Я разбираю его на ZonedDateTime, но при форматировании он отображается как GMT-04:00, а не EST, как я ожидал.

Почему это происходит - могу ли я заставить его отображать ожидаемый часовой пояс?

Пример

final String dateString = "16/07/2017 19:28:33 EST";
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss z");

System.out.println(MessageFormat.format("Input - {0}", dateString));
System.out.println(MessageFormat.format("Parsed - {0}", formatter.format(ZonedDateTime.parse(dateString, formatter))));

Выход:

Input - 16/07/2017 19:28:33 EST
Parsed - 16/07/2017 19:28:33 GMT-04:00

Мой часовой пояс GMT. Принять OpenJDK 14.0.2.12, локаль en_GB.

Для контекста я пытаюсь лучше понять эту проблему в последних версиях Amazon Corretto 11 — https://github.com/corretto/corretto-11/issues/147


person Jakg    schedule 21.03.2021    source источник
comment
Я думаю, вы могли бы добавить .withZone(ZoneId.of("EST")) к DateTimeFormatter.ofPattern(...)   -  person Lino    schedule 21.03.2021
comment
Является ли GMT-4 часовым поясом, в котором вы сейчас находитесь?   -  person daniu    schedule 21.03.2021
comment
@daniu нет - я по Гринвичу.   -  person Jakg    schedule 21.03.2021
comment
@Savior AdoptOpenJDK 14.0.2.12, локаль en_GB.   -  person Jakg    schedule 22.03.2021
comment
Я воспроизвел с помощью Locale.UK. Интересно. Он анализирует в 2017-07-16T19:28:33-04:00[America/New_York], что неудивительно, но затем форматирует в 16/07/2017 19:28:33 GMT-04:00, что, честно говоря, для меня.   -  person Ole V.V.    schedule 22.03.2021


Ответы (2)


tl;dr

Вы сказали:

он отображается как GMT-04:00, а не EST, как я ожидал.

Такие детали зависят от того, действует ли Locale.UK или нет.

  • 16/07/2017 19:28:33 GMT-04:00Locale.UK
  • 16/07/2017 19:28:33 EDTLocale.US
  • 16/07/2017 19:28:33 HAELocale.CANADA_FRENCH

➥ Для текстового обмена данными о дате и времени: (a) придерживайтесь стандартных форматов ISO 8601, и (b) использовать нулевое смещение, когда это целесообразно. Это делает спорным проблему № 147.

Подробности

Кстати, старайтесь избегать парсинга текста даты и времени с использованием псевдозон из 2–4 букв, таких как EST, EDT, IST, CST. Это нестандартные, неуникальные(!), слабые попытки дать подсказку относительно часового пояса и Действует летнее время (DST).

Используйте только зоны реального времени в формате Continent/Region, например Europe/London.


Вы сказали:

а не EST, как я ожидал

Летнее время (DST) действовало в эту дату и время в часовом поясе America/New_York, а не стандартное время< /а>. Таким образом, вы должны ожидать EDT, а не EST.


Я предлагаю вам не усложнять ситуацию, встраивая вызовы в ваши println операторы.

Вы должны указать Locale, а не неявно полагаться на текущую локаль JVM по умолчанию, которая может измениться в любой момент во время выполнения. Обратите внимание, как я добавил .withLocale( locale ) к формированию объекта DateTimeFormatter. Я указал Locale.UK, потому что вы упомянули en_GB в комментарии.

Итак, давайте изменим ваш код на это:

final Locale locale = Locale.US ;  // Locale.UK versus Locale.US yield different outputs.
final String input = "16/07/2017 19:28:33 EST";
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "dd/MM/yyyy HH:mm:ss z" ).withLocale( locale ) ;
final ZonedDateTime zdt = ZonedDateTime.parse( input , formatter ) ;
final String zdtToString = zdt.toString() ;
final String zdtFormatted = zdt.format( formatter ) ;

… а также:

// Dump to console.
System.out.println( "input: " + input ) ;
System.out.println( "zdt: " + zdt ) ;
System.out.println( "zdtToString: " + zdtToString ) ;
System.out.println( "zdtFormatted: " + zdtFormatted ) ;

См. выполнение кода в реальном времени на IdeOne.com на Java 12.

input: 16/07/2017 19:28:33 EST
zdt: 2017-07-16T19:28:33-04:00[America/New_York]
zdtToString: 2017-07-16T19:28:33-04:00[America/New_York]
zdtFormatted: 16/07/2017 19:28:33 GMT-04:00

Если мы изменим эту локаль с Locale.UK на Locale.US, мы получим другой результат.

zdtFormatted: 16/07/2017 19:28:33 EDT
person Basil Bourque    schedule 21.03.2021

tl;dr

Никогда не используйте тип парсера/форматера даты и времени (класс) без Locale.

import java.text.MessageFormat;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

class Main {
    public static void main(String[] args) {
        final String dateString = "16/07/2017 19:28:33 EST";
        final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss z", Locale.ENGLISH);

        System.out.println(MessageFormat.format("Input - {0}", dateString));
        System.out.println(
                MessageFormat.format("Parsed - {0}", formatter.format(ZonedDateTime.parse(dateString, formatter))));
    }
}

Вывод:

Input - 16/07/2017 19:28:33 EST
Parsed - 16/07/2017 19:28:33 EDT

ОНЛАЙН-ДЕМО

person Arvind Kumar Avinash    schedule 21.03.2021
comment
Ваш ответ заставил меня понять, что ввод, показанный в вопросе, на самом деле неверен, с EST, а не EDT. - person Basil Bourque; 22.03.2021