SimpleDateFormat .format() дает разные результаты в Java8 и Java11

У меня есть этот небольшой фрагмент кода:

import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {

    public static void main(String[] args) {

        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");

        System.out.println(format.format(new Date()));

    }
}

С Java 8 вывод:

Tue, 16 Jul 2019 13:16:54 AEST

С Java 11:

Tue., 16 Jul. 2019 13:16:54 AEST

В чем разница и как мне изменить свой код, чтобы он работал одинаково в обеих версиях Java?

На самом деле я использовал Руль, обнаружив эту проблему, и я мог сузить ее до версии Java, но было бы здорово знать, как использовать Handlebars для получения того же результата для той же строки формата...)

Я рекомендую вам не использовать SimpleDateFormat и Date. Эти классы плохо спроектированы и давно устарели, а первые, как известно, доставляют много хлопот. Вместо этого используйте DateTimeFormatter и, например, ZonedDateTime, оба из java.time, современный API даты и времени Java.

Ole V.V. 16.07.2019 05:42

Какая у вас локаль по умолчанию? Также спрашиваю, потому что я не думаю, что встречал локаль, где точка (точка) после аббревиатур английского языка (Tue и Jul) была бы правильной.

Ole V.V. 16.07.2019 05:43

Возможный дубликат JDK dateformatter анализирует DayOfWeek в немецкой локали, java8 против java9 и/или Анализ времени с помощью LocalTime. Короче говоря, это из-за CLDR.

Ole V.V. 16.07.2019 05:45

Мой регион en_AU

Siaynoq 16.07.2019 05:46

Локаль, используемая в последней ссылке, stackoverflow.com/questions/56814020/…, тоже en-AU. Вы захотите прочитать комментарии, даже если они немного длинные.

Ole V.V. 16.07.2019 05:48
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
5
4 782
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

TL;DR

Запустите Java 9 и более поздние версии (включая Java 11) с системным свойством java.locale.providers, определенным следующим образом:

java -Djava.locale.providers=COMPAT,CLDR YourApp

Теперь вывод без точек, в том же формате, что и на Java 8, например:

Tue, 16 Jul 2019 14:24:15 AEST

КЛДР

Java получает данные о локали, включая сокращения, используемые для дней недели и месяцев на разных языках, из четырех источников. До Java 8 по умолчанию использовались собственные данные локали Java. Данные локали из Java 8 из репозитория Unicode Common Locale Data Repository (CLDR; см. ссылки внизу) также включены, а из Java 9 они используются по умолчанию. Собственные данные Java по-прежнему включены и доступны, если указать COMPAT в вышеуказанном системном свойстве. Нам нужно поставить его первым в строке, так как источники проверяются по очереди.

Можно было бы ожидать, что другим (и, возможно, даже более приятным) решением будет использование CLDR во всех версиях Java. Любопытно, что в данном случае это не дает нам одинаковый формат для всех версий Java. Вот результат при установке свойства на CLDR,JRE (JRE — это старое название COMPAT, в Java 8 нам нужно использовать его вместо этого).

На Java 8:

Tue, 16 Jul 2019 14:35:02 AEST

На Java 9 и 11:

Tue., 16 Jul. 2019 14:35:52 AEST

CLDR поставляется в различных версиях, и разные версии Java включаются в разные версии.

Java.время

Вот фрагмент, который я использовал для вышеуказанных выходных данных.

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
            "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.forLanguageTag("en-AU"));
    ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Australia/Sydney"));
    System.out.println(now.format(formatter));

Я использую и рекомендую java.time, современный API даты и времени Java. Классы даты и времени, которые вы использовали, SimpleDateFormat и Date, давно устарели и всегда были плохо спроектированы, поэтому я рекомендую избегать их. В Java 8 и более поздних версиях, безусловно, нет причин, по которым мы должны их использовать, и java.time также был перенесен в Java 6 и 7.

Ссылки

Большое спасибо за исчерпывающее объяснение - я ценю время, которое вы потратили на ответ. Это причина, по которой я посещаю (и публикую) stackoverflow! +1 за ваши забавные заголовки (tl;dr / cldr) :D

Siaynoq 16.07.2019 13:47

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