В чем смысл локали в DateTimeFormatter?

Учитывая следующий код


LocalDate localDateEpoch = LocalDate.parse(
        "01-Jan-2017", DateTimeFormatter.ofPattern("d-MMM-yyyy", Locale.FRENCH));

System.out.println("localDateEpoch: " + localDateEpoch);

Причина, по которой я выбрал французский, заключается в том, что французские цифры латинские, поэтому теоретически они должны просто интерпретировать это (то же самое с буквами в «Jan»). Тем не менее я получил эту ошибку

Exception in thread "main" java.time.format.DateTimeParseException: 
                             Text '01-Jan-2017' could not be parsed at index 3

Мои вопросы

  • Первое: (связанное с локалью) Что случилось с отсутствием стран/языков? Они очень ограничены
  • 2-й: (связанный с локалью) Почему существуют локали для языков/стран (например, French и France)?
  • 3-й: Что это вообще делает?

Теперь я провел небольшое исследование со своей стороны. Кажется, чтобы решить упомянутую выше проблему отсутствия языков, вы могли бы просто сделать Locale.forLanguageTag("fa");, но опять же, почему бы не сделать Locale.Iran/Persian. Видел сообщение, в котором упоминалось, как в этом случае преобразовать числовые значения в персидский язык, поэтому я попытался сделать наоборот.

    LocalDate localDateEpoch = LocalDate.parse(
        "۰۱-Jan-۲۰۱۷", DateTimeFormatter.ofPattern("d-MMM-yyyy", Locale.forLanguageTag("fa")));

И снова у меня возникла ошибка.

Exception in thread "main" java.time.format.DateTimeParseException: 
                             Text '۰۱-Jan-۲۰۱۷' could not be parsed at index 0

Также, если вам интересно, я попробовал без MMM и все равно получил ту же ошибку.

используйте форматтер с разными локалями, чтобы отформатировать дату и время, и посмотрите, есть ли разница - что вы подразумеваете под «отсутствием стран/языков»?

user85421 02.07.2024 19:55

@user85421 user85421 Я попробовал это с японским языком. Кажется, они также используют латиницу, но не работает. кроме того, попробовал еще и с персидским/французским. А под «отсутствием стран/языков» (как уже упоминалось) я имею в виду отсутствие стран, как почти во всех странах Ближнего Востока (Иран, Катар, Пакистан, Турция и т. д.).

ryn 02.07.2024 19:57

Эксперимент для вас: используйте тот же DateTimeFormatter, чтобы отформатировать январь LocalDate на французском языке.

Sotirios Delimanolis 02.07.2024 20:02

попробуйте LocalDate.of(2017, 1, 1).format(DateTimeFormatter.ofPattern("d-MMM-yyyy", Locale.FRENCH)) посмотреть, какой формат/значения ожидаются вместо "01-Jan-2017"

user85421 02.07.2024 20:10

@ user85421 Ах, великолепно, я действительно делал это раньше с ofLocalizedDate, и у меня это не сработало, поэтому я предположил, что это не будет иметь значения, но кажется [выход: 1 января.-2017], что январь на самом деле janv теперь я подумал, что МММ - это всего лишь ограничение в три символа, и вы бы увеличили это значение (это также дало ошибку), похоже, это та же самая причина, по которой японский язык не будет работать, поскольку это то же самое, но работает Германия как это (январь)

ryn 02.07.2024 20:15

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

Sotirios Delimanolis 02.07.2024 20:18

если вам нужны арабские цифры и есть идеи, проверьте Как преобразовать дату с английского на арабский ... или найдите [java] [date] arabic

user85421 02.07.2024 20:19

Спойлер: "01.01.2017"

trashgod 02.07.2024 20:23

Аналогично: Разница в инициализации объекта Locale

Basil Bourque 09.07.2024 21:06
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
9
145
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я просто собираюсь быстро суммировать то, что @sotirios-delimanolis и @user85421 сказали в комментариях.

Вопросы и Ответы

  • Первое: (связанное с локалью) Что случилось с отсутствием стран/языков? Они очень ограничены. Не совсем понимаю, почему не все языки доступны как переменные класса Locale. однако вы можете просто обойти это ограничение с помощью Locale.forLanguageTag("fa") (например).
  • Второе: (связано с локалью) Почему существуют локали для языков/стран (например, французского и Франции)? Упоминается здесь Но TLDR: такие языки, как французский и немецкий, имеют дочерние компании, поэтому для fr-CA (канадский французский) следует использовать специальный французский язык, который по сути не совсем совпадает с французским французским.
  • Третий: Что это вообще дает? Предоставляет альтернативный способ хранения дат. Судя по моему тестированию, это изменяет параметр «Месяц», который вы могли бы использовать localizedBy Для цифровых букв. По крайней мере, на персидском языке этот разговор был английским представлением, а не названием месяца, указанным в календаре.

См. также stackoverflow.com/questions/5621852/…

Sotirios Delimanolis 02.07.2024 20:34
Ответ принят как подходящий

вр; доктор

Просто игнорируйте устаревшие константы, такие как Locale.CANADA и Locale.CANADA_FRENCH.

Вместо этого используйте статические фабричные методы.

Locale.of( "fr" , "FR" )  // French, France
Locale.of( "fr" , "CA" )  // French, Canada

Подробности

В чем смысл локали в DateTimeFormatter?

Языковой стандарт определяет две вещи, необходимые для локализации:

  • Человеческий язык
    (французский, фарси, кантонский диалект и т. д.)
  • Культурные нормы
    (аббревиатура, пунктуация, порядок элементов и т.д.)

КЛДР

Современная Java по умолчанию получает информацию о локали из Common Locale Data Repository (CLDR) , опубликованного Консорциумом Unicode . Копия CLDR включена в состав JDK / JRE. Обновления JDK/JRE часто сопровождаются обновлениями CLDR. Правила внутри CLDR меняются по мере развития человеческого языка и культурных норм.

Более старые версии Java имели более простой ограниченный набор информации/правил локали. CLDR обеспечивает почти всемирный охват, а также определяет многие субкультуры.

Что касается Locale.of, локаль используется при переводе названия месяца, дня и т. д. И локаль определяет, как сокращать эти имена, если это необходимо. Кроме того, в языковом стандарте есть правила использования знаков препинания, например, в некоторых языках для завершения аббревиатуры используется ТОЧКА (DateTimeFormatter), а в других языках — нет.

Не обращайте внимания на константы .

Что случилось с отсутствием стран/языков?

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

Эти константы были определены на заре истории Java . Они были предназначены для удобства. Но я сомневаюсь, что сегодня они будут добавлены в Java API по нескольким причинам. Позже команда Java рекомендовала игнорировать эти константы. Здесь задан еще один вопрос: Как были выбраны константы локали?. Но удовлетворительного ответа там не было. Я бы посоветовал вам помнить, что Java спешно выходила на рынок во времена веб-мании, и некоторые сомнительные решения были приняты в спешке. К счастью, сегодня Java развивается с гораздо большим вниманием.

См. Учебные пособия по Java от Oracle (бесплатно) для получения информации о создании экземпляра объекта Locale: Создание локали . И прочитайте Javadoc для локали. Обратите внимание, что Java 19+ предлагает методы Locale в качестве статических фабрик для объектов of.

Почему существуют локали для языков/стран (например, французского и Франции)?

(A) Как отмечалось выше, вам следует игнорировать особенности констант Locale.

(Б) Указывая страну, вы получаете не только язык, но и определенный набор культурных норм. Например, жители Франции и Квебека используют французский язык, но у них сложились разные культурные нормы.

Пример кода

Вы сказали:

Locale

Не жестко закодируйте формат при локализации. Весь формат может варьироваться в зависимости от культуры. Вместо этого позвольте java.time определить подходящий формат для каждой локали.

Чтобы программно запрограммировать форматы при локализации, вызовите методы DateTimeFormatter.ofPattern("d-MMM-yyyy", Locale.FRENCH).

System.out.println( Runtime.version( ) );

List < Locale > locales =
        List.of(
                Locale.of( "fr" , "FR" ) ,  // French, France
                Locale.of( "fr" , "CA" ) ,  // French, Canada
                Locale.of( "en" , "US" ) ,  // English, United States
                Locale.of( "fa" , "IR" )    // Farsi, Iran
        );

LocalDate today = LocalDate.now( ZoneId.of( "America/Edmonton" ) );
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate( FormatStyle.MEDIUM );
for ( Locale locale : locales )
{
    String output = today.format( formatter.withLocale( locale ) );
    System.out.println( locale + " = " + output );
}

При запуске обратите внимание, что французская локализация для Канады сокращает название июля месяца иначе, чем французская локализация для Франции.

Обратите внимание, как в английской локализации для США переупорядочиваются элементы. А в фарси-иранской локализации используется еще третий порядок.

22.0.1+10
fr_FR = 2 juil. 2024
fr_CA = 2 juill. 2024
en_US = Jul 2, 2024
fa_IR = 2 ژوئیه 2024

Кстати, в примерах здесь используется ISO 8601 версия Григорианского календаря , определенная в IsoChronology в комплекте с инфраструктурой java.time в Java. Возможно, вашему приложению потребуется использовать другую хронологию. Например, для реальной работы на фарси Ирана вы можете использовать Хронологию , реализующую исламский календарь. В комплекте с Java вы найдете пять реализаций DateTimeFormatter.ofLocalized…. Еще десять вы можете найти в библиотеке ThreeTen-Extra. Также могут существовать дополнительные сторонние реализации.

Ваши ошибки в коде

java.time.format.DateTimeParseException: текст «01 января 2017 г.» не удалось проанализировать по индексу 3

Ваш текстовый ввод включает в себя начальный нуль для дня месяца. Но ваш шаблон форматирования использует код Chronology. Этот одиночный d указывает на то, что для однозначных чисел, таких как d, не будет начального заполняющего нуля. Итак, ваш вклад 1 нарушает ваше обещание 01-.

Ваш шаблон форматирования не соответствует введенным вами данным другим способом.

1-

В текстовом поле есть "01-Jan-2017", DateTimeFormatter.ofPattern("d-MMM-yyyy", Locale.FRENCH) для названия месяца. А вот по-французски название месяца будет Jan. Если бы синтаксический анализ перешел к этой части входных данных, вы бы столкнулись с еще одним исключением синтаксического анализа .

Избегайте анализа локализованного текста. Для текстового обмена значениями даты и времени используйте только стандартные форматы ISO 8601. Эти форматы были специально созданы для обмена данными, чтобы их было легко анализировать машинам, а также легко читать людям разных культур.

Удобно, что классы java.time по умолчанию используют стандартные форматы ISO 8601 при синтаксическом анализе/генерации текста. Поэтому нет необходимости определять какой-либо шаблон форматирования для стандартных вводов/выводов.

[РЕДАКТИРОВАНИЕ: кажется, это скорее «отображение» (тот же результат с правильным форматом), так что следите] Я бы кое-что добавил - и это тот факт, что формат ISO не кажется совсем правильным. Я написал свой собственный код, и даже глядя на ваш результат (говоря о времени по персидскому календарю), на самом деле это не так, как вы могли бы увидеть, как это делают местные люди/веб-сайты. лучше было бы гггг-МММ-дд, но мое тестирование показывает дд-МММ-гггг, а ваше — ддд-гггг-МММ . Тот же формат, о котором я упоминал, также хранится на официальных правительственных сайтах, поэтому я не совсем уверен, что с этим делать, но я решил упомянуть об этом.

ryn 03.07.2024 16:54

@ryn (A) Я не могу понять первое предложение твоего комментария. (B) Что касается альтернативных персидских форматов, CLDR использует правила, соответствующие каноническому академическому пониманию текущих культурных практик. Конечно, со временем эта практика может измениться, и некоторые люди могут счесть CLDR старомодным. А некоторые организации могут диктовать определенные форматы, особенно если они работают с аудиторией, не входящей в их собственную культуру. Если это ваша ситуация, вы можете указать конкретный формат, используя Locale для перевода. Звоните DateTimeFormatter#withLocale.

Basil Bourque 03.07.2024 23:58

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