ТЛ; др
«Почему» не имеет значения, поскольку фреймворки и API, обеспечивающие такие значения по умолчанию, являются общими для всех.
Всегда передавайте ZoneId
& Locale
явно, даже если это необязательно.
LocalDate.now( ZoneId.of( "Africa/Tunis" ) )
... и ...
DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL )
.withLocale( Locale.JAPAN )
Укажите необязательные аргументы
Мало того, что текущий часовой пояс JVM по умолчанию и локаль находятся вне вашего контроля как программиста (исходя из хост-ОС или из параметров запуска JVM), они могут измениться в любой момент во время выполнения. Любой код в любом потоке любого приложения в JVM может изменить либо зону по умолчанию, либо локаль.
Лучше всегда явно указывайте желаемую / ожидаемую зону или локаль , передавая необязательные аргументы, а не неявно полагайтесь на текущее значение по умолчанию JVM.
Часовой пояс
Часовой пояс имеет решающее значение при определении даты. В любой момент времени дата меняется по всему земному шару в зависимости от зоны. Например, через несколько минут после полуночи в Париж Франция - новый день, а еще «вчера» в Монреаль Квебек .
Если часовой пояс не указан, JVM неявно применяет свой текущий часовой пояс по умолчанию. Это значение по умолчанию может измениться в любой момент, поэтому ваши результаты могут отличаться. Лучше явно указать желаемый / ожидаемый часовой пояс в качестве аргумента.
Укажите собственное имя часового пояса в формате continent/region
, например America/Montreal
, Africa/Casablanca
или Pacific/Auckland
. Никогда не используйте 3-4-буквенное сокращение, такое как EST
или IST
, поскольку они не истинные часовые пояса, не стандартизированы и даже не уникальны (!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
Если вы хотите использовать текущий часовой пояс JVM по умолчанию, запросите его и передайте в качестве аргумента. Если опущено, текущее значение по умолчанию JVM применяется неявно. Лучше быть явным, поскольку значение по умолчанию может быть изменено в любой момент во время выполнения любым кодом в любом потоке любого приложения в JVM.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Locale
Класс DateTimeFormatter
может автоматически локализоваться при генерации строки, представляющей значение даты-времени.
Instant instant = Instant.now(); // Current moment in UTC with a resolution of up to nanoseconds.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z ); // Adjust from UTC to a specific time zone. Same moment, different wall-clock time.
Для локализации укажите:
FormatStyle
для определения длины или сокращения строки.
Locale
для определения (а) человеческого языка для перевода названия дня, названия месяца и т. Д., И (б) культурных норм, решающих вопросы сокращения, капитализации, пунктуации, разделители и тому подобное.
Пример: * 1 077 *
ZoneId z = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
Locale l = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( l );
String output = zdt.format( f );
Примечания
Кстати, обратите внимание, что при обработке даты и времени проблемы часового пояса и локали различны, ортогональны. Первый определяет значение или содержание значения даты и времени, второй управляет его форматированием для отображения. Вы можете настроить отображение момента Квебека в японском формате или отображение момента Индии в норвежском формате.
Допустим, на ваших серверах разработки и производства настроен TimeZone GMT + 2.
Вообще говоря, серверы должны быть настроены на UTC. Но, как обсуждалось выше, никогда не полагайтесь на это. Передайте желаемый / ожидаемый часовой пояс в качестве аргументов, даже если вы хотите использовать UTC.
2-часовая смена может быть нелегко наблюдать сразу.
Теперь вы можете выполнять тестирование проще с java.time , передавая альтернативные реализации класса Clock
. Этот класс сам по себе предоставляет альтернативные варианты поведения, такие как установка фиксированного времени или установка часов на много часов / минут впереди или позади истинного времени.
Скорее всего, вам потребуется переписать некоторый код, чтобы сообщить о зоне, локали или кодировке с помощью какого-либо внедрение-зависимости . Это может быть так же просто, как передача аргументов в раздел кода.
И хотя вы можете передавать TimeZone в свои календари, API могут создавать экземпляры календарей (или дат) с использованием часового пояса по умолчанию.
Кажется, что очень распространенная проблема, что программисты игнорируют проблему часового пояса и локали. Вероятно, из-за невежества, а не из-за лени.
Здесь нет волшебной пули, кроме:
- Обучите своих программистов обработке даты и времени, локализации и кодированию символов .
- Установите стандарт для вашей команды, настаивая на том, чтобы зона, локаль и кодировка символов всегда были явными. Если требуется значение по умолчанию, сделайте явный вызов, чтобы получить значение по умолчанию.
Я согласен с мнением, связанным с вашим Вопросом. Фреймворки и API никогда не должны предоставлять значения по умолчанию для часового пояса, локали и кодировки символов , по моему скромному мнению. Полагаясь на такие настройки по умолчанию, не задумываясь программистами, это источник некоторых самых неприятных неуловимых ошибок времени выполнения. Но, c’est la vie , нам приходится иметь дело с реальностью как есть.