Учитывая следующий код
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
French
и France
)?Теперь я провел небольшое исследование со своей стороны.
Кажется, чтобы решить упомянутую выше проблему отсутствия языков, вы могли бы просто сделать 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 user85421 Я попробовал это с японским языком. Кажется, они также используют латиницу, но не работает. кроме того, попробовал еще и с персидским/французским. А под «отсутствием стран/языков» (как уже упоминалось) я имею в виду отсутствие стран, как почти во всех странах Ближнего Востока (Иран, Катар, Пакистан, Турция и т. д.).
Эксперимент для вас: используйте тот же DateTimeFormatter
, чтобы отформатировать январь LocalDate
на французском языке.
попробуйте LocalDate.of(2017, 1, 1).format(DateTimeFormatter.ofPattern("d-MMM-yyyy", Locale.FRENCH))
посмотреть, какой формат/значения ожидаются вместо "01-Jan-2017"
@ user85421 Ах, великолепно, я действительно делал это раньше с ofLocalizedDate
, и у меня это не сработало, поэтому я предположил, что это не будет иметь значения, но кажется [выход: 1 января.-2017], что январь на самом деле janv
теперь я подумал, что МММ - это всего лишь ограничение в три символа, и вы бы увеличили это значение (это также дало ошибку), похоже, это та же самая причина, по которой японский язык не будет работать, поскольку это то же самое, но работает Германия как это (январь)
В Javadoc класса подробно описано, что означают символы шаблона и как их количество меняет поведение. Есть несколько случаев.
если вам нужны арабские цифры и есть идеи, проверьте Как преобразовать дату с английского на арабский ... или найдите [java] [date] arabic
Спойлер: "01.01.2017"
Аналогично: Разница в инициализации объекта Locale
Я просто собираюсь быстро суммировать то, что @sotirios-delimanolis и @user85421 сказали в комментариях.
Locale
. однако вы можете просто обойти это ограничение с помощью Locale.forLanguageTag("fa")
(например).localizedBy
Для цифровых букв. По крайней мере, на персидском языке этот разговор был английским представлением, а не названием месяца, указанным в календаре.См. также stackoverflow.com/questions/5621852/…
Просто игнорируйте устаревшие константы, такие как 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 (A) Я не могу понять первое предложение твоего комментария. (B) Что касается альтернативных персидских форматов, CLDR использует правила, соответствующие каноническому академическому пониманию текущих культурных практик. Конечно, со временем эта практика может измениться, и некоторые люди могут счесть CLDR старомодным. А некоторые организации могут диктовать определенные форматы, особенно если они работают с аудиторией, не входящей в их собственную культуру. Если это ваша ситуация, вы можете указать конкретный формат, используя Locale
для перевода. Звоните DateTimeFormatter#withLocale
.
используйте форматтер с разными локалями, чтобы отформатировать дату и время, и посмотрите, есть ли разница - что вы подразумеваете под «отсутствием стран/языков»?