ZonedDateTime.parse() не работает для той же строки в Windows, но работает в Mac и Linux.

Следующий UnitTest дает сбой при выполнении через IntelliJ IDE на компьютере с Windows (Java 11.0.9), но проходит успешно при выполнении на компьютере Mac или Linux с той же версией Java.

@Test
public void rfc1123JaveTimeUtilParsing(){
    final String rfc1123Pattern = "EEE, dd MMM yyyy HH:mm:ss z";
    final String responseTimeStamp = "Mon, 14 Dec 2020 20:34:37 GMT";

    DateTimeFormatter javaTimeDateTimeFormatter = DateTimeFormatter.ofPattern(rfc1123Pattern);
    ZonedDateTime javaFinalTime = ZonedDateTime.parse(responseTimeStamp, javaTimeDateTimeFormatter);
    Assert.assertNotNull(javaFinalTime);
}

Для окон результатом является следующее исключение:

java.time.format.DateTimeParseException: текст «Пн, 14 декабря 2020 г., 20:34:37 ​​по Гринвичу» не может быть проанализирован по индексу 0

попробуйте указать Locale: DateTimeFormatter.ofPattern(rfc1123Pattern, Locale.UK)

Youcef LAIDANI 18.12.2020 21:01

Добавление к комментарию @YCF_L DateTimeFormatter.ofPattern(String) использует «локаль FORMAT по умолчанию». который основан на том, который вы указали в своей ОС, поэтому, если ваш компьютер с Windows и ваш компьютер с Mac или Linux имеют разные локали, форматер будет давать разные результаты.

Marcono1234 18.12.2020 21:54

@YCF_L — для тестов в большинстве случаев Locale.ROOT будет лучшим выбором, если только вы не тестируете вещи, специфичные для конкретной локали. Но Locale.UK было бы хорошей отправной точкой для этого вопроса…

tquadrat 18.12.2020 22:47

Спасибо, ребята, за ответы. Locale.ENGLISH решил проблему.

Ariel Vazquez 21.12.2020 12:50
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
Что такое управление транзакциями JDBC и как оно используется для поддержания согласованности данных?
Что такое управление транзакциями JDBC и как оно используется для поддержания согласованности данных?
Управление транзакциями JDBC - это мощная функция, которая позволяет рассматривать группу операций с базой данных как единую единицу работы. Оно...
Выполнение HTTP-запроса с помощью Spring WebClient: GET
Выполнение HTTP-запроса с помощью Spring WebClient: GET
WebClient - это реактивный веб-клиент, представленный в Spring 5. Это реактивное, неблокирующее решение, работающее по протоколу HTTP/1.1.
Gradle за прокси-сервером
Gradle за прокси-сервером
Создайте проект Gradle под сетевым прокси.
2
4
518
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Никогда не используйте DateTimeFormatter без Locale.

Поскольку данная дата и время указаны на английском языке, вы должны использовать DateTimeFormatter с Locale.ENGLISH.

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

public class Main {
    public static void main(String[] args) {
        final String responseTimeStamp = "Mon, 14 Dec 2020 20:34:37 GMT";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
        ZonedDateTime zdt = ZonedDateTime.parse(responseTimeStamp, dtf);
        System.out.println(zdt);
    }
}

Выход:

2020-12-14T20:34:37Z[GMT]

По умолчанию DateTimeFormatter#ofPattern использует локаль FORMAT по умолчанию, которую JVM устанавливает во время запуска в зависимости от среды хоста. Я попытался проиллюстрировать проблему с помощью следующей демонстрации:

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

public class Main {
    public static void main(String[] args) {
        final String responseTimeStamp = "Mon, 14 Dec 2020 20:34:37 GMT";
        DateTimeFormatter dtfWithDefaultLocale = null;

        System.out.println("JVM's Locale: " + Locale.getDefault());
        // DateTimeFormatter with the default Locale
        dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z");
        System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
        System.out.println(
                "Parsed with JVM's default locale: " + ZonedDateTime.parse(responseTimeStamp, dtfWithDefaultLocale));

        // DateTimeFormatter with Locale.ENGLISH explicitly (recommended)
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
        ZonedDateTime zdt = ZonedDateTime.parse(responseTimeStamp, dtf);
        System.out.println("Parsed with Locale.ENGLISH: " + zdt);

        // Setting the JVM's default locale to Locale.FRANCE
        Locale.setDefault(Locale.FRANCE);
        System.out.println("JVM's Locale: " + Locale.getDefault());
        // DateTimeFormatter with the default Locale
        dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z");
        System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
        System.out.println(
                "Parsed with JVM's default locale: " + ZonedDateTime.parse(responseTimeStamp, dtfWithDefaultLocale));
    }
}

Выход:

JVM's Locale: en_GB
DateTimeFormatter's Locale: en_GB
Parsed with JVM's default locale: 2020-12-14T20:34:37Z[GMT]
Parsed with Locale.ENGLISH: 2020-12-14T20:34:37Z[GMT]
JVM's Locale: fr_FR
DateTimeFormatter's Locale: fr_FR
Exception in thread "main" java.time.format.DateTimeParseException: Text 'Mon, 14 Dec 2020 20:34:37 GMT' could not be parsed at index 0
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
    at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:598)
    at Main.main(Main.java:29)

Большое спасибо за очень подробное объяснение и примеры. Я включил Locale в свой тест, и это решило проблему. Я из Аргентины, и служба находится в США. Так что использования Locale.ENGLISH было достаточно.

Ariel Vazquez 21.12.2020 12:50

Другие вопросы по теме