Несовместимая чувствительность к регистру в Java по сравнению с Bash - PullRequest
0 голосов
/ 22 мая 2018

Когда я пытаюсь отформатировать дату на польском языке, я получаю согласованное форматирование:

new SimpleDateFormat("EEEE", Locale.forLanguageTag("pl-PL")).format(new Date())

приводит к

wtorek

Тот же результат в bash:

LC_ALL=pl_PL
$ date +"%A %b %d"
wtorek maj 22

Обратите внимание на то, что строчные буквы w в wtorek.

Когда я делаю это для чешского языка, результат является нечувствительным:

new SimpleDateFormat("EEEE", Locale.forLanguageTag("cs-CZ").format(new Date())

приводит к

Pondělí

При запуске в bash:

$ LC_ALL=cs_CZ 
$ date +"%A %b %d"
pondělí kvě 21

Обратите внимание на верхний регистр P в результате Java.Как это произошло?Означает ли это, что SimpleDateFormat не использует стандартные локали, установленные в системе?

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Java собирает данные о локалях (включая названия дней недели в разных локалях) из четырех источников.И да, операционная система хоста является одной из них, но не по умолчанию.Цитируя документацию LocaleServiceProvider :

Среда выполнения Java предоставляет следующие четыре региональных стандарта:

  • "CLDR": поставщик на основеПроект Консорциума Unicode CLDR.
  • "COMPAT": представляет службы, чувствительные к локали, которые совместимы с предыдущими выпусками JDK до JDK8 (аналогично JRE JDK8).
  • "SPI":представляет службы, чувствительные к локали, реализующие подклассы этого класса LocaleServiceProvider.
  • «HOST»: поставщик, отражающий пользовательские настройки пользователя в базовой операционной системе.Этот поставщик может быть недоступен, в зависимости от реализации среды выполнения Java.
  • «JRE»: представляет синоним «COMPAT».Это имя устарело и будет удалено в следующем выпуске JDK.

До Java 8 JRE было по умолчанию.Я использую java.time, потому что никто не должен возиться с устаревшими SimpleDateFormat:

    DateTimeFormatter dayOfWeekFormatter 
            = DateTimeFormatter.ofPattern("EEEE", Locale.forLanguageTag("cs-CZ"));
    LocalDate date = LocalDate.now(ZoneId.of("Europe/Prague"));
    System.out.println(date.format(dayOfWeekFormatter));

Вывод, запущенный на моем Oracle jdk1.8.0_131, согласуется с вашим результатом (заглавными буквами S):

Středa

Мы можем контролировать данные локали, используемые через системное свойство.Например, чтобы предпочесть CLDR, либо запустите программу с параметром командной строки VM -Djava.locale.providers=CLDR,COMPAT, либо вставьте следующую строку в начале программы:

    System.setProperty("java.locale.providers", "CLDR,COMPAT");

středa

Теперь мы получаем строчную букву s.

Моя оболочка в macOS Sierra 10.12.6 просто выдает Wednesday, поэтому, очевидно, моя ОС не имеет данных о чешском языке (что звучит странно; вероятно,вопрос где-то еще), и, следовательно, не вариант для меня.Вы можете попробовать поставить HOST перед приведенной выше строкой провайдера локали и посмотреть, соответствует ли то, что вы получаете, вашему bash.

В Java 9 и более поздних версиях CLDR используется по умолчанию.Таким образом, выполнение того же фрагмента на jdk9.0.4 без установки какого-либо системного свойства также дает день недели в нижнем регистре:

středa

0 голосов
/ 22 мая 2018

Означает ли это, что SimpleDateFormat не использует стандартные локали, установленные в системе

Да, системные локали не используются, и доступные локали зависят от поставщика JVM / JRE.Например, проверьте lib\ext\localedata.jar в каталоге JRE.После распаковки вы можете найти файл: sun\text\resources\cs\FormatData_cs_CZ.class, который декомпилируется в:

public class FormatData_cs extends ParallelListResourceBundle
{
    @Override
    protected final Object[][] getContents() {
        return new Object[][] { { "MonthNames", 
        { "ledna", "\u00fanora", "b\u0159ezna", "dubna", "kv\u011btna", "\u010dervna", "\u010dervence", "srpna", "z\u00e1\u0159\u00ed", "\u0159\u00edjna", "listopadu", "prosince", "" } }, 
        { "standalone.MonthNames", { "leden", "\u00fanor", "b\u0159ezen", "duben", "kv\u011bten", "\u010derven", "\u010dervenec", "srpen", "z\u00e1\u0159\u00ed", "\u0159\u00edjen", "listopad", "prosinec", "" } }, 
        { "MonthAbbreviations", { "Led", "\u00dano", "B\u0159e", "Dub", "Kv\u011b", "\u010cer", "\u010cvc", "Srp", "Z\u00e1\u0159", "\u0158\u00edj", "Lis", "Pro", "" } }, 
        { "standalone.MonthAbbreviations", { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "" } }, 
        { "MonthNarrows", { "l", "\u00fa", "b", "d", "k", "\u010d", "\u010d", "s", "z", "\u0159", "l", "p", "" } },
        { "standalone.MonthNarrows", { "l", "\u00fa", "b", "d", "k", "\u010d", "\u010d", "s", "z", "\u0159", "l", "p", "" } }, 
        { "DayNames", { "Ned\u011ble", "Pond\u011bl\u00ed", "\u00dater\u00fd", "St\u0159eda", "\u010ctvrtek", "P\u00e1tek", "Sobota" } }, 
        { "standalone.DayNames", { "ned\u011ble", "pond\u011bl\u00ed", "\u00fater\u00fd", "st\u0159eda", "\u010dtvrtek", "p\u00e1tek", "sobota" } }, 
        { "DayAbbreviations", { "Ne", "Po", "\u00dat", "St", "\u010ct", "P\u00e1", "So" } }, 
        { "standalone.DayAbbreviations", { "ne", "po", "\u00fat", "st", "\u010dt", "p\u00e1", "so" } }, 
        { "DayNarrows", { "N", "P", "\u00da", "S", "\u010c", "P", "S" } }, 
        { "standalone.DayNarrows", { "N", "P", "\u00da", "S", "\u010c", "P", "S" } },
        { "AmPmMarkers", { "dop.", "odp." } }, 
        { "Eras", { "p\u0159.Kr.", "po Kr." } }, 
        { "short.Eras", { "p\u0159. n. l.", "n. l." } }, 
        { "narrow.Eras", { "p\u0159.n.l.", "n. l." } }, 
        { "NumberElements", { ",", " ", ";", "%", "0", "#", "-", "E", "\u2030", "\u221e", "\ufffd" } }, 
        { "TimePatterns", { "H:mm:ss z", "H:mm:ss z", "H:mm:ss", "H:mm" } }, 
        { "DatePatterns", { "EEEE, d. MMMM yyyy", "d. MMMM yyyy", "d.M.yyyy", "d.M.yy" } }, 
        { "DateTimePatterns", { "{1} {0}" } }, 
        { "DateTimePatternChars", "GuMtkHmsSEDFwWahKzZ" } };
    }
}

и содержит "Pond \ u011bl \ u00ed" в "DayNames".

...