Избегайте часовой пояс настройки по умолчанию
Как мудро советовали в вопросе, вы должны установить часовой пояс в JVM по умолчанию только последнее средство в самой отчаянной ситуации. Установка значения по умолчанию затрагивает весь код во всех потоках всех приложений, запущенных в этой JVM, и сразу же затрагивает их при их выполнении (!).
Вместо этого во всей вашей работе с датой всегда передавайте необязательный аргумент часового пояса различным методам. Никогда не полагайтесь на действующую по умолчанию зону JVM.
Избегайте классов старой даты и времени
Старые устаревшие классы даты и времени в комплекте с самыми ранними версиями Java доказали, плохо разработаны, хлопотно, и сбивает с толку. Избежать их. Теперь вытесняется классами java.time.
Итак, вместо java.util.Date
, используйте java.time.Instant
. Класс Instant
представляет собой момент на временной шкале в UTC с разрешением nanoseconds. Этот класс Instant
является основным строительным блоком обработки даты и времени. Используйте этот класс часто, так как большая часть вашей бизнес-логики, хранения данных, обмена данными и работы с базами данных должна быть в UTC. Не думайте о UTC, как о другом варианте часового пояса, скорее, о UTC, как о One True Time. Во время программирования забывайте о своем собственном местном часовом поясе, поскольку это ограниченное мышление путает ваше программирование.
Instant
Вообще говоря, ваш веб-сервис должен принять и дать значения UTC. Класс Instant
может непосредственно анализировать и генерировать строки для представления этих значений в стандартном формате ISO 8601.
Instant instant = Instant.parse("2016-09-09T22:34:08Z");
String output = instant.toString(); // Generates: 2016-09-09T22:34:08Z
Так что не нужно манипулировать этими значениями UTC. Держите их вокруг. Служба предоставления данных должна придерживаться UTC по большей части.
В вашем случае DTOS, будучи DTOs, должны придерживаться хранения значений в формате UTC (либо Instant
объекта или строки в формате ISO 8601 в формате UTC с Z
на конце). By definition, DTO должен быть «глупым» в смысле отсутствия бизнес-объекта и вместо этого должен просто переносить базовые элементы данных. Другие объекты, потребляющие эти DTO, должны обрабатывать любые необходимые назначения часового пояса.
ZonedDateTime
Генерация строки в других часовых поясах только для представления пользователям. Здесь мы назначаем часовой пояс Квебека для просмотра момента через линзу другого wall-clock time.Примените ZoneId
, чтобы получить ZonedDateTime
. ZonedDateTime
и Instant
обе представляют в тот же момент в истории, в то же время на шкале времени.
ZoneId z = ZoneId.of("America/Montreal");
ZonedDateTime zdt = instant.atZone(z);
Обратите внимание, что мы держим Instant
объекта вокруг в нашей бизнес-объекте, без изменений. Мы генерируем отдельный отдельный объект, ZonedDateTime
, для другого времени настенных часов.
- При выполнении этих заданий в часовом поясе в вашем коде пройдите около
ZoneId
объектов.
- При указании этих назначений часовых поясов через API веб-службы передайте имя часового пояса в виде строки. Всегда используйте proper IANA ‘tz’ time zone names в формате
continent/region
, например America/Montreal
или Pacific/Auckland
. Никогда не используйте аббревиатуру 3-4 буквы, такую как EST
или IST
, поскольку они не являются настоящими часовыми поясами, а не стандартизированы и даже не уникальны (!).
Генерация строки
Когда веб-служба , обслуживающие данные потребляться как данные, а не представления, генерировать строки в формате ISO 8601. Классы java.time используют эти стандартные форматы по умолчанию для разбора и генерации строк. Просто вызовите toString
, чтобы сгенерировать строку в стандартном формате. Обратите внимание, что ZonedDateTime
расширяет стандартный формат, добавляя имя часового пояса в квадратных скобках.
String output = instant.toString(); // 2016-09-09T22:34:08Z
String output = zdt.toString(); // 2016-09-09T19:34:08-03:00[America/Montreal]
Когда ваш веб-сервис служит информации для представления к пользователю, а не для потребления в качестве данных, генерировать строки в формате, соответствующие человеческом язык пользователя и культурные нормы. Вы можете указать конкретный формат. Но в целом лучше всего позволить java.time автоматически локализовать для вас.
Locale locale = Locale.CANADA_FRENCH;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).withLocale(l);
String output = zdt.format(f);
Для большей ясности вы считаете, что используете один стандартный часовой пояс? Скажите UTC? Поскольку вы упомянули, что ваши абоненты предоставляют часовой пояс, могут ли они быть преобразованы в UTC? Таким образом, JVM и другой часовой пояс Пользователей не имеют значения? –
Спасибо за ответ. Дата всегда будет сохранена с часовым поясом по умолчанию (UTC), однако для того, чтобы сделать запрос типа, будет отправлен , который будет вести учет времени для UTC для пользователя. – mPissolato