Нужна ли "Локаль" для разбора строк даты и времени в Java?

  • при каких условиях мне нужен Locale для разбора строк даты и времени в Java?
  • какое отношение язык имеет к часовой пояс?

иногда я вижу вопросы и ответы, где Локаль была необходима для решения проблемы разбора. Но в других нет упоминания о местности.

1 ответов


локаль и часовой пояс не связаны

локаль и часовой пояс отдельный, ортогональных проблемы с обработкой даты и времени.

  • Locale
    • язык
      человеческий язык, например арабский, французский, фарси. Текст названий дней недели, названий месяцев и порядковые показатели. Для пример... это Monday или Lundi?
    • культура
      обычно используемые идиомы в организации фрагментов текста и чисел, составляющих строковое представление значения даты-времени. Например... в краткой форме, это month-date-year, date-month-year или year-month-date? В длинной форме, день недели на первом месте? Название месяца заглавной буквы или все с маленькой буквы? Имеет ли аббревиатура ПОЛНАЯ ОСТАНОВКА (ТОЧКА) символ или нет?
  • Часовой Пояс
    • смещение
      количество часов и минут разница между стена времени используется людьми в одной области из UTC ( GMT), основное время, стандарт, по которому мир регулирует часы и время.
    • аномалии
      история изменений, внесенных в смещение, применяемое в настоящее время правила, определяющие смещение, включая такие корректировки, как летнее время (DST), и подтвердил планы на изменения в ближайшем будущем.

таким образом, вы можете смешивать и сочетать локаль и часовой пояс. Ниже приводятся некоторые примеры.

  • французский человек, посещающий конференцию в Пуне Индии, должен увидеть расписание сессий в настенное время Индии, но предпочел бы читать " понедельник "как" Ланди", его родной французский.
    • французский язык
    • Индия часовой пояс
  • бразильский инженер, работающий в Сиэтле, хочет посмотреть прямую трансляцию вебинара из Турку в Финляндии. Она должна знать, когда указать свой веб-браузер на вебинар. Ей нужно знать время начала в Финляндии после адаптации к часовому поясу Сиэтла, но с бразильским языком для отображения на ее родном португальском языке.
    • Локаль ("pt" , "БР") для презентации (для генерации текстового представления)
    • запланированное время начала в Финляндии должно быть скорректировано с Europe/Helsinki to America/Los_Angeles (часовой пояс Сиэтла).
  • газета в Исландии может сообщить о событии, которое произошло в России, как две даты-время, Московский часовой пояс и для ясности добавления часового пояса UTC. Но в статье будет использоваться исландский язык для текста, включая день недели.
    • Москва часовой пояс и локаль Исландии
    • часовой пояс UTC и локаль Исландии

при синтаксическом анализе / генерации строки, которая является текстовым представлением значения даты-времени, Локаль используется только в двух ситуациях:

  • название дня недели и / или название месяца (или порядковый индикатор, но лучше всего избегать их)
  • мягкое кодирование, локализованное форматирование

в первом случае, если ваша строка содержит такие слова, как"Monday"/" Lundi "или"March"/" Mars", для перевода этих строк используется Локаль.

во втором случае, если у вас нет явного шаблона форматирования, то Локаль используется для того, чтобы знать ожидаемый порядок частей дня недели, даты, имени месяца, года и так далее. Например, там, где англоязычные американцы говорят "11 октября", франкоязычные канадцы используют обратный порядок "11 октября". Под софт-кодированием мы подразумеваем что-то вроде DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ) по сравнению с жестко закодированным форматом, таким как DateTimeFormatter.ofPattern("yyyy MM dd, EEE")

Итак, когда Locale не требуется? Если у вас есть входная строка со всеми цифрами, например "2015-01-23", и вы жестко кодируете формат"гггг-ММ-ДД"...

String input = "2015-01-23";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyy-MM-dd")

...тогда Локаль фактически не имеет значения. У вас нет слов для перевода, нет "понедельника" или "Ланди". И не просят использовать локализованный форматтер, который будет нуждаться в локали, чтобы знать, если дата приходит до или после месяца, и другие подобные детали.

обратите внимание, что вы все еще можете указать локаль в такой ситуации. Действительно, я рекомендую вам сделать привычка всегда указывать Locale (и часовой пояс).

Неявная Локаль И Часовой Пояс

Итак, почему вы видите так много связанных с датой вопросов и ответов на StackOverflow без какой-либо локали? Потому что если опущено, текущая локаль JVM по умолчанию применяется автоматически и молча.

поэтому, если у вас есть строка с английским текстом, работающим на JVM, установленном в US locale, то нет проблем. Но такая зависимость от неявной локали не рекомендуется. Если какой-либо код в любом потоке любого приложения во время работы звонки Locale.setDefault, и влияют на весь другой код в этой JVM. Затем ваш код создает исключение. Лучше иметь привычку явно указывать ожидаемую / желаемую локаль.

тот же совет для часового пояса. Если опущено, текущий часовой пояс JMV по умолчанию применяется автоматически и молча. Опять же, любой код в любом потоке любого приложения во время работы можно назвать TimeZone.setDefault, и влияют на весь другой код в этой JVM. Затем ваш код создает исключение или ведет себя неожиданно.

Surprise-changes-at-runtime должно быть достаточно оснований, чтобы иметь привычку всегда указывать как локаль, так и часовой пояс. Но еще одно преимущество заключается в том, что он также делает ваш код самодокументируемыми. Кроме того, сознательное указание локали и часового пояса во время программирования может предупредить вас о неправильных или неподтвержденных предположениях.

Пример

ZoneId zoneIdIstanbul = ZoneId.of( "Europe/Istanbul" );
ZonedDateTime zdtIstanbul = ZonedDateTime.of( 2015, 10, 11, 12, 30, 00, 0, zoneIdIstanbul );  // Half-past noon in Turkey.

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

Locale locale_tr_TR = new Locale( "tr", "TR" );
DateTimeFormatter formatter_tr_TR = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale_tr_TR );
String outputTurkish = formatter_tr_TR.format( zdtIstanbul );

наш бизнесмен знает, что клиент использует координатора логистики в Финляндии, поэтому она печатает то же значение даты и времени в Финляндии. Итак, у нас есть Турция часовой пояс с финским языком.

Locale locale_fi_FI = new Locale( "fi", "FI" );
DateTimeFormatter formatter_fi_FI = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale_fi_FI );
String outputFinnish = formatter_fi_FI.format( zdtIstanbul );

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

таким образом, этот следующий код отличается тем, что нам нужно настроить часовой пояс и локаль. Тот же момент на временной шкале, дата-время ожидаемой доставки, но представлен по-разному в тексте. Обратите внимание, как на этот раз мы добавляем дополнительный вызов withZone в конце цепочки создание форматера, где мы указываем настройку часового пояса для переопределения назначенной зоны объекта ZonedDateTime.

Locale locale_fr_CA = Locale.CANADA_FRENCH;
ZoneId zoneId_Montréal = ZoneId.of( "America/Montreal" );
DateTimeFormatter formatter_fr_CA_Adjusted = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale_fr_CA ).withZone( zoneId_Montréal );
String outputQuébec = formatter_fr_CA_Adjusted.format( zdtIstanbul );

наконец, ради нашего английский язык-говорящие читатели StackOverflow.com, давайте сделаем версию на английском языке. Но обратите внимание, что мы перерабатываем Québec formatter, сохраняя уже установленный часовой пояс, но заменяя локаль на локаль Соединенных Штатов. (Технически не переработка, но так сказать. Использование неизменяемые объекты означает, что новый объект создается со значениями, основанными на старом объекте.)

Locale locale_en_US = Locale.US;
DateTimeFormatter formatter_US_Unadjusted = formatter_fr_CA_Adjusted.withLocale( locale_en_US );
String output_US_Unadjusted = formatter_US_Unadjusted.format( zdtIstanbul );

давайте посмотрим выходные данные этих значений. Дамп для консоли.

Сначала мы неявно вызываем toString способ на нашем