Как получить значение ZoneOffset по умолчанию в java8?

С java8 мы знаем, что использование ZoneId.default() может получить системный по умолчанию ZoneId, но как получить стандартный ZoneOffset?

Я вижу, что у ZoneId есть некоторые "правила", а у каждого правила есть ZoneOffset, означает ли это, что у ZoneId может быть более одного ZoneOffset?

Ответ 1

ТЛ; др

OffsetDateTime.now().getOffset()

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

ZoneId.systemDefault() 

Смещение относительно часового пояса

смещение от UTC - это просто число часов, минут и секунд - не более того. Например, -08:00 означает восемь часов после UTC, а +05:45 означает пять часов сорок пять минут до 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(): America/Los_Angeles

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[America/Montreal]

zoneOffsetXmas.toString(): -05:00

zoneOffsetXmas.getTotalSeconds(): -18000

Table of date-time types in Java, both modern and legacy.

ZoneId

Как предложено в комментарии yanys, вы можете опросить ZoneId для конкретного ZoneOffset, передав момент как Instant. Класс Instant представляет момент на временной шкале в UTC с разрешением наносекунд (до девяти (9) цифр десятичной дроби).

Это просто еще один маршрут к тому же пункту назначения. Как и в рассмотренных выше OffsetDateTime и ZonedDateTime, мы указываем (а) часовой пояс и (б) момент.

Instant instant = zdtXmas.toInstant();
ZoneOffset zo = z.getRules().getOffset( instant );

For ZoneId: America/Montreal at instant: 2017-12-25T05:00:00Z the ZoneOffset is: -05:00

См. все эти примеры кода в прямом эфире на IdeOne.com.

ZoneOffset.systemDefault - Ошибка или функция?

Класс ZoneOffset, подкласс ZoneId, задокументирован как наследующий метод systemDefault. Тем не менее, это на самом деле не работает.

ZoneOffset zoneOffset = ZoneOffset.systemDefault() ;  // Fails to compile.

ошибка: несовместимые типы: ZoneId не может быть преобразован в ZoneOffset

Не уверен, является ли эта ошибка компиляции ошибкой или функцией. Как обсуждалось выше, мне кажется, не имеет смысла просить о смещении по умолчанию с указанием даты и времени, поэтому, возможно, ZoneOffset.systemDefault действительно должен потерпеть неудачу. Но в документации должно быть так с объяснением.

Я попытался сообщить об ошибке, если документ не смог решить эту проблему, но не смог определить, где и как подать такой отчет об ошибке.

Солнечное время против политического времени

Еще немного о смещениях и часовых поясах...

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

В солнечное время, когда вы путешествуете из города в город, двигаясь на запад, полдень наступает немного позже. Двигаясь на восток, полдень наступает немного раньше. Таким образом, у каждого города есть свой собственный полдень, разделяемый только с городами на север и юг вдоль одной и той же долготы.

Солнечное время было в значительной степени заброшено в современную эпоху. Когда прибыли поезда, телеграфы и телефоны, возникла необходимость во временной координации. Таким образом, точка была выбрана для ближайшего солнечного времени полудня, и было объявлено, что большая полоса суши в стольких милях к западу и востоку имеет одни и те же 12:00 на часах, такое же число смещение часов вперед или назад по линии гринвичского простого меридиана line. Так началась традиция, когда на каждой остановке поезда были видные часы, чтобы город знал стандартное время для своего большого региона, а не солнечное время для своего города. Как правило, в городах на западном краю этого часового пояса часы на вокзале показываются за 12:00 до захода солнца. Часы в городах на восточной окраине региона показываются в 12:00 чуть позже солнца.

Политики всего мира проявили склонность к изменению смещения (й) своей юрисдикции. Причины разные, такие дипломатия, война и занятие и глупость перехода на летнее время (DST). Причины меняются, но их изменения происходят с удивительной частотой. Часовой пояс - это имя, данное региону для отслеживания его истории таких изменений. Таким образом, смещение от UTC всего на несколько часов-минут-секунд впереди или позади основного меридиана. Часовой пояс - это гораздо больше: история прошлого, настоящего и будущего меняется на смещения определенного региона. Хотя два соседних региона могут сегодня иметь одинаковое смещение от UTC, в прошлом или будущем они могут различаться в зависимости от прихотей или логики их политиков.

Это означает, что современное отслеживание времени, определяемое политиками, имеет мало общего с географией. Например, огромная страна Индии сегодня имеет один часовой пояс (смещение от UTC до +05: 30). Таким образом, солнечный полдень (солнце прямо над вашей головой) находится в разных местах на огромном субконтиненте. Политики Индии решили, что это поможет объединить их разнообразную демократию. В других примерах по всему миру мы видим, что регионы используют свой часовой пояс в качестве символа для международных отношений, таких как отличия от своей оскорбительной соседней страны или выбор той же зоны в качестве соседа, что и отношения оттепели, как это недавно наблюдалось в Северной Корее, чтобы соответствовать Южная Корея. Итак, в настоящее время солнечное время является лишь одним из нескольких соображений в отслеживании времени.


О java.time

Среда java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar и & SimpleDateFormat.

Проект Joda-Time, который теперь находится в режиме обслуживания, рекомендует выполнить переход на классы java.time.

Чтобы узнать больше, см. Учебное пособие по Oracle. И поищите в Кару множество примеров и объяснений. Спецификация: JSR 310.

Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, совместимый с JDBC 4.2 или более поздней версией. Нет необходимости в строках, нет необходимости в классах java.sql.*.

Где взять классы java.time?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11 и более поздние версии - часть стандартного Java API с встроенной реализацией ,
    • Java 9 добавляет некоторые мелкие функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 & 7 в ThreeTen-Backport.
  • Android

Table of which java.time library to use with which version of Java or Android

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и еще.