Как я могу преобразовать строку часового пояса в объект TimeZone в Java?
У меня есть строки часового пояса сервала в формате utc, такие как "UTC+08:00", "UTC-05:00", вопрос в том, как я могу преобразовать эти строки формата utc в объект TimeZone (java.util.TimeZone) в яве?
я попытался преобразовать по zoneId следующим образом, но не сработало:
ZoneId zoneId = ZoneId.of("UTC+08:00");
TimeZone timeZone = TimeZone.getTimeZone(zoneId);
я знаю TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
будет работать, но я не знаю соответствие между "UTC + 08: 00" и "Азия / Шанхай"
3 ответа
ТЛ; др
- Не использовать
TimeZone
класс (теперь наследство). - использование
ZoneOffset
а такжеZoneId
вместо.
Пример:
ZoneOffset.of( "+08:00" )
использование java.time.ZoneId
не TimeZone
Проблемные старые классы даты и времени, включенные в ранние версии Java, теперь унаследованы, заменены классами java.time. Среди этих старых классов наследия TimeZone
теперь вытесняется ZoneId
а также ZoneOffset
,
Смещение от UTC - это количество часов и минут, корректируемое до или после UTC. Это представлено ZoneOffset
учебный класс.
Часовой пояс - это набор смещений, история изменений смещения, используемых конкретным регионом при определении времени их настенных часов. Это представлено ZoneId
учебный класс.
Использование часового пояса всегда предпочтительнее, чем смещение, поскольку зона имеет смещение, а также намного больше информации. Но ваши примеры - всего лишь смещения. Так что используйте ZoneOffset
разобрать строки после удаления символов UTC
,
String input = "UTC+08:00".replace( "UTC" , "" ) ;
ZoneOffset offset = ZoneOffset.of( input ) ;
Не угадать часовой пояс
Вы не можете предполагать, что конкретное смещение подразумевает определенный часовой пояс. Многие зоны могли использовать конкретное смещение в прошлом, настоящем или будущем. Так что не стоит угадывать зону.
Взять, к примеру, смещение +08:00
, Это смещение в настоящее время используется несколькими различными часовыми поясами, включая Asia/Shangai
, Asia/Macao
, а также Australia/Perth
,
Если вы уверены, что определенная зона была предназначена для значения даты и времени, примените ее, чтобы получить ZonedDateTime
, Но не угадай.
Instant
Класс представляет момент на временной шкале в UTC с разрешением наносекунд.
Instant instant = Instant.now() ;
ZoneId z = ZoneId.of( "Asia/Shanghai" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Если вы точно не знаете предполагаемый часовой пояс и имеете только смещение, используйте смещение, чтобы получить OffsetDateTime
,
Instant instant = Instant.now() ;
ZoneOffset offset = ZoneOffset.of( "+08:00" ) ;
OffsetDateTime odt = instant.atOffset( offset ) ;
Перерабатывать
Лучше всего избегать старого унаследованного класса TimeZone
, Но если вы должны использовать этот класс для работы со старым кодом, еще не обновленным для классов java.time, вы можете преобразовать в / из ZoneId
, Используйте новые методы преобразования, добавленные к старым классам.
TimeZone myLegacyTimeZone = TimeZone.getTimeZone( myModernZoneId );
…а также…
ZoneId z = myLegacyTimeZone.toZoneId() ;
Обратите внимание, что ZoneOffset
это подкласс ZoneId
, Обычно мы игнорируем эти отношения наследования. Если у вас есть только простое смещение, такое как +08:00
использовать ZoneOffset
, Если у вас есть полный часовой пояс, такой как Asia/Shanghai
использовать ZoneId
, Единственное исключение из этого правила для этого преобразования в / из TimeZone
где только суперкласс ZoneId
признается
Если вы удалите UTC, вы можете проанализировать его как ZoneOffset, который расширяет ZoneId
ZoneId zoneId = ZoneOffset.of("+08:00")
Так как вы можете использовать современные классы в java.time
пакет, я рекомендую вам придерживаться их и избегать устаревших классов, таких как TimeZone
, SimpleDateFormat
а также Date
, Я в основном повторяю то, что @Basil Bourque уже сказал в своем ответе, но также хотел продемонстрировать, насколько хорошо его предложение вписывается в ваш контекст:
DateTimeFormatter format = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm");
ZonedDateTime dateTime = LocalDateTime.parse(dateTimeString, format).atZone(zoneId);
Instant i = dateTime.toInstant();
System.out.println(dateTime + " -> " + i);
Я также продемонстрировал, что вы можете преобразовать ZonedDateTime
для Instant
в случае, если вам это нужно. Отпечатки фрагментов
2017-05-05T05:05+08:00[UTC+08:00] -> 2017-05-04T21:05:00Z
Если вы уверены, что ваша строка даты и времени совпадает, то нет необходимости проходить через String.replace()
для удаления UTC
с начала строки зоны.
Я анализирую строку независимо от часового пояса, а затем объединяю ее с информацией о смещении зоны. Я думаю, что это более естественно, чем знать зону для разбора.
В случае, если вам нужен старомодный Date
Например, для вызова какого-то устаревшего кода это достаточно просто:
Date d = Date.from(i);
Старые классы хлопотны
Несмотря на то, что я знаю, что старые классы имеют тенденцию показывать нежелательное поведение, не говоря вам, что что-то не так, я все равно был отрицательно удивлен, узнав, что код в вашем вопросе не работает. Это дает часовой пояс GMT! Документально подтверждено, что это возможно, однако, в документации TimeZone.getTimeZone(ZoneId)
:
Возвращает:
указанная часовая зона или зона GMT, если данный идентификатор не может быть понят.
Можно все еще задаться вопросом, как простой часовой пояс, как UTC+08:00
может быть "не понято".