JSR310 Как интернационализировать шаблон для месяца? - PullRequest
3 голосов
/ 28 марта 2020

Я пытаюсь отформатировать дату без года (только день и месяц, например, 12.10 )

DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT) для меня все еще год года (12.10.20).

поэтому я попытался DateTimeFormatter.ofPattern("dd. MM"), но это, очевидно, порядок и точка жестких кодов, которые не будут радовать американских пользователей. (которые ожидают косые черты и месяц сначала)

Как я могу интернационализировать шаблон ? Есть ли какой-то абстрактный синтаксис для разделителей и т. Д. c?

Ответы [ 2 ]

1 голос
/ 29 марта 2020

Ну, как отметил Оле, нет 100% -ного решения, использующего только java.time. Но моя библиотека Time4J нашла решение, основанное на данных хранилища CLDR (ICU4J также предоставляет поддержку), используя тип AnnualDate (в качестве замены MonthDay):

LocalDate yourLocalDate = ...;
MonthDay md = MonthDay.from(yourLocalDate);
AnnualDate ad = AnnualDate.from(md);

ChronoFormatter<AnnualDate> usStyle =
  ChronoFormatter.ofStyle(DisplayMode.SHORT, Locale.US, AnnualDate.chronology());
ChronoFormatter<AnnualDate> germanStyle =
  ChronoFormatter.ofStyle(DisplayMode.SHORT, Locale.GERMANY, AnnualDate.chronology());
System.out.println("US-format: " + usStyle.format(ad)); // US-format: 12/31
System.out.println("German: " + germanStyle.format(ad)); // German: 31.12.
1 голос
/ 29 марта 2020

Я не думаю, что можно найти решение, которое дает 100% удовлетворительные результаты для всех регионов. Давайте все равно попробуем.

    Locale formattingLocale = Locale.getDefault(Locale.Category.FORMAT);
    String formatPattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
            FormatStyle.SHORT, null, IsoChronology.INSTANCE, formattingLocale);

    // If year comes first, remove it and all punctuation and space before and after it
    formatPattern = formatPattern.replaceFirst("^\\W*[yu]+\\W*", "")
            // If year comes last and is preceded by a space somewhere, break at the space
            // (preserve any punctuation before the space)
            .replaceFirst("\\s\\W*[yu]+\\W*$", "")
            // Otherwise if year comes last, remove it and all punctuation and space before and after it
            .replaceFirst("\\W*[yu]+\\W*$", "");
    DateTimeFormatter monthDayFormatter
            = DateTimeFormatter.ofPattern(formatPattern, formattingLocale);

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

    LocalDate exampleDate = LocalDate.of(2020, Month.DECEMBER, 31);
    System.out.format(formattingLocale, "%-11s %s%n",
            exampleDate.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)),
            exampleDate.format(monthDayFormatter));     

Вывод в Французский язык (Locale.FRENCH):

31/12/2020  31/12

В Locale.GERMAN:

31.12.20    31.12

Редактировать: Моя немецкая подруга сообщает мне, что это неправильно. Мы всегда должны писать точку после каждого из двух чисел, потому что оба являются порядковыми числами. Мено Хохшильд, немецкий автор другого ответа, также выдает 31.12. с двумя точками для немецкого языка.

In Locale.US:

12/31/20    12/31

Это может сделать американских пользователей счастливыми. В Swedi sh (Locale.forLanguageTag("sv")):

2020-12-31  12-31

В комментарии я упомянул болгарский (bg):

31.12.20 г. 31.12

Насколько я понял, «г.» (Кириллица c г и точка) - это сокращение от слова, которое означает год , поэтому, пропуская год, мы, вероятно, должны также пропустить это сокращение. Я сомневаюсь, стоит ли ставить точку после 12.

Наконец, венгерский (hr):

31. 12. 2020. 31. 12.

Как работает код: Мы сначала запрашивают DateTimeFormatterBuilder о шаблоне формата короткой даты для локали. Я предполагаю, что это шаблон, который ваш форматер из вопроса также использует за кулисами (не проверял). Затем я использую разные регулярные выражения для удаления года из разных вариантов, см. Комментарии в коде. Год может быть представлен как y или u, поэтому я принимаю во внимание оба (на практике используется y). Теперь тривиально создать новый форматер из измененного шаблона. Для болгар: с моей точки зрения, в регулярных выражениях Java есть ошибка, они не распознают буквы кириллицы c как символы слова, поэтому г тоже был удален (ошибка есть и в документации, это утверждает, что слово-символ [a-zA-Z_0-9]). Нам повезло, однако, в нашем случае это дает желаемый результат.

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

Ссылка: Документация Java регулярных выражений (регулярное выражение)

...