Как получить ZoneOffset по умолчанию в java8?
С java8 мы знаем использование ZoneId.default()
может получить системное значение по умолчанию ZoneId
, но как получить дефолт ZoneOffset
?
Я вижу, что ZoneId
имеет некоторые "правила", и каждое правило имеет ZoneOffset
Это означает, что ZoneId
может иметь более одного ZoneOffset
?
1 ответ
ТЛ; др
OffsetDateTime.now().getOffset()
Смещение против часового пояса
Смещение от UTC - это просто число часов, минут и секунд - не более того.
Часовой пояс - это история смещений для определенного региона, а также набор правил для обработки аномалий, таких как переход на летнее время (DST), которые вызывают сдвиги в смещении за определенные периоды времени.
Часовой пояс = (История смещений + Правила для аномалий)
Так что лучше использовать зону, когда известно.
Смещение для любого региона меняется со временем. Например, летнее время в Соединенных Штатах смещает смещение на час примерно на полгода, а затем восстанавливает этот час обратно на смещение в течение другой половины года. Вся цель часового пояса - документировать эти сдвиги в смещении.
Так что на самом деле нет смысла просить о смещении без даты-времени. В America/Los_Angeles
Например, в части этого года смещение -08:00
но в другую часть года это -07:00
во время летнего времени.
OffsetDateTime
Итак, давайте определим момент как OffsetDateTime
, а затем извлечь ZoneOffset
,
OffsetDateTime odt = OffsetDateTime.now ();
ZoneOffset zoneOffset = odt.getOffset ();
odt.toString(): 2017-01-02T15: 19: 47.162-08: 00
zoneOffset.toString(): -08: 00
Тот now
Метод на самом деле неявно применяет текущий часовой пояс JVM по умолчанию. Я предлагаю вам всегда делать это явно, указав желаемый / ожидаемый часовой пояс. Даже если вам нужна текущая зона по умолчанию, скажите об этом явно, чтобы прояснить свои намерения. Устраните неоднозначность того, предполагали ли вы заданный по умолчанию или не учли часовой пояс, как это часто случается с программистами. Вызов ZoneId.systemDefault
,
OffsetDateTime odt = OffsetDateTime.now ( ZoneId.systemDefault () );
ZoneOffset zoneOffset = odt.getOffset ();
ZoneId.systemDefault(). ToString(): Америка / Лос-Анджелес
odt: 2017-01-02T15: 19: 47.162-08: 00
zoneOffsetOfOdt: -08: 00
Предупреждение о зависимости от зоны по умолчанию: это значение по умолчанию может быть изменено в любой момент любым кодом в любом потоке в JVM. Если важно, спросите пользователя о предполагаемом часовом поясе.
Вы можете запросить смещение для его количества времени как общее количество секунд.
int offsetSeconds = zoneOffset.getTotalSeconds ();
offsetSeconds: -28800
ZonedDateTime
Другой пример: возможно, вы хотите знать, какой будет компенсация на Рождество в этом году в Квебеке. Укажите часовой пояс America/Montreal
, получить ZonedDateTime
, попросите его смещение как ZoneOffset
объект.
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate ld = LocalDate.of( 2017 , 12 , 25 );
ZonedDateTime zdtXmas = ld.atStartOfDay( z );
ZoneOffset zoneOffsetXmas = zdtXmas.getOffset();
zdtXmas.toString(): 2017-12-25T00: 00-05: 00 [Америка / Монреаль]
zoneOffsetXmas.toString(): -05:00
zoneOffsetXmas.getTotalSeconds (): -18000
ZoneId
Как предложено в комментарии yanys, вы можете опросить ZoneId
для конкретного ZoneOffset
передавая момент как Instant
, Instant
класс представляет момент на временной шкале в UTC с разрешением наносекунд (до девяти (9) цифр десятичной дроби).
Это просто еще один маршрут к тому же пункту назначения. Так же, как с OffsetDateTime
а также ZonedDateTime
Как было сказано выше, мы указываем (а) часовой пояс и (б) момент.
Instant instant = zdtXmas.toInstant();
ZoneOffset zo = z.getRules().getOffset( instant );
Для ZoneId: Америка / Монреаль в момент времени: 2017-12-25T05:00:00Z, ZoneOffset: -05:00
Смотрите код всех этих примеров в прямом эфире на IdeOne.com.
ZoneOffset.systemDefault
- Ошибка или особенность?
ZoneOffset
класс, подкласс ZoneId
документируется как наследование systemDefault
метод. Тем не менее, это на самом деле не работает.
ZoneOffset zoneOffset = ZoneOffset.systemDefault() ; // Fails to compile.
ошибка: несовместимые типы: ZoneId не может быть преобразован в ZoneOffset
Не уверен, является ли этот сбой при компиляции ошибкой или функцией. Как уже говорилось выше, для меня не имеет смысла просить о смещении по умолчанию с указанием даты и времени, поэтому, возможно, ZoneOffset.systemDefault
должен действительно потерпеть неудачу. Но документация должна так сказать с объяснением.
Я попытался сообщить об ошибке, если документ не смог решить эту проблему, но не смог определить, где и как подать такой отчет об ошибке.
О java.time
Инфраструктура java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые классы даты и времени, такие как java.util.Date
, Calendar
& SimpleDateFormat
,
Проект Joda-Time, находящийся сейчас в режиме обслуживания, рекомендует перейти на классы java.time.
Чтобы узнать больше, смотрите Oracle Tutorial. И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310.
Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, соответствующий JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.*
классы.
Где взять классы java.time?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11 и более поздние версии - часть стандартного API Java со встроенной реализацией.
- Java 9 добавляет некоторые незначительные функции и исправления.
- Java SE 6 и Java SE 7
- Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport.
- Android
- Более поздние версии Android связывают реализации классов java.time.
- Для более ранних версий Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). Смотрите Как использовать ThreeTenABP….
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь, такие как Interval
, YearWeek
, YearQuarter
и многое другое.
В зависимости от вашей цели вы можете обойтиZoneOffset
целиком.
Предполагая, что вам просто нужен ZoneOffset
например, для LocalDateTime.ofEpochSecond()
, вы можете заменить
ZoneOffset offset = OffsetDateTime.now().getOffset();
LocalDateTime dt1 = LocalDateTime.ofEpochSecond(seconds, 0, offset);
с участием
LocalDateTime dt2 = LocalDateTime.ofInstant(
Instant.ofEpochSecond(seconds),
ZoneId.systemDefault());
где dt1.equals(dt2)
является true
.