Як отримати ZoneOffset за замовчуванням у Java8?


80

З java8 ми знаємо, що use ZoneId.default()може отримати системний за замовчуванням ZoneId, але як отримати за замовчуванням ZoneOffset?

Я бачу, що a ZoneIdмає деякі "правила", і кожне правило має a ZoneOffset, це означає, що a ZoneIdможе мати більше одного ZoneOffset?


спробуватиZoneOffset.systemDefault()
Шубхем Чаурасія

2
Багато часових поясів мають різні зміщення через літній час.
Марк Філіпп

15
ZoneOffset.systemDefault()повертає a ZoneId.
Марк Філіпп

3
Поточний ZoneOffset є функцією ZoneId та Instant. ZoneOffset current = zone.getRules().getOffset(instant)
Олександр Янишин

3
@FredSuvn Я вважаю, що Яніс розуміє, що немає сенсу вимагати компенсації без зазначення часового поясу та моменту (значення дати та часу). Приклад: Перехід на літній час в даний час America/Los_Angelesспричиняє зміщення -08:00, але змінюється на -07:00літо. Отже, ви не можете вимагати компенсації, не сказавши, коли воно діє та для якого часового поясу . Див. Мою відповідь для подальшого обговорення.
Василь Бурк

Відповіді:


186

tl; д-р

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, отримайте a 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

Таблиця типів дати та часу в Java, як сучасних, так і застарілих.

ZoneId

Як запропоновано в коментарі yanys, ви можете допитати a 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дійсно повинно провалитися. Але в документації повинно бути так, з поясненнями.

Я намагався подати повідомлення про помилку, оскільки документ не міг вирішити цю проблему, але відмовився, не маючи можливості визначити, де і як подати такий звіт про помилку.

Сонячний час проти політичного часу

Трохи більше про зміщення та часові пояси ...

Сонячний час використовувався з попередньої історії, відстежуючи кожен день, відзначаючи, коли сонце прямо над головою. Засуньте палицю в землю і спостерігайте за її тінню. Коли тінь найкоротша, коли тінь починає рости, а не стискатися, ви знаєте, що зараз полудень. Формалізуйте це за допомогою сонячного годинника, щоб відстежувати години.

З сонячним часом, коли ви їдете з міста в місто, рухаючись на захід, полудень приходить трохи пізніше. Рухаючись на схід, полудень приходить трохи раніше. Отже, кожне місто має власний полудень, спільний лише для міст на півночі та півдні на одній довготі.

У сучасну епоху сонячний час був в основному відмовлений. Коли прибували поїзди, телеграфи та телефони, виникала і необхідність тимчасової координації. Отож, точка була вибрана для ближнього сонячного часу полудня, і велика ділянка суші на стільки миль на захід і на схід оголошено всім поділяти однакові 12:00 на годиннику, таку ж кількість годин, зміщених вперед або за лінією Грінвічського первинного меридіана . Так розпочалася традиція, що кожна зупинка поїздів видно демонструє годинник, щоб місто знало стандартний час для свого більшого регіону, а не сонячний час для власного міста. Як правило, у містах на західній околиці цього часового поясу годинник залізничного вокзалу буде читатись 12:00 трохи ранішесонце над головою. Годинники в містах на східному краю області показують 12:00 трохи після того, як сонце над головою.

Політики у всьому світі виявляли схильність до зміни відступу своєї юрисдикції. Причини різні, такі як дипломатія, війна та окупація, а також глупота літнього часу . Причини різні, але їх зміни відбуваються з дивовижною частотою. Часовий пояс - це назва регіону для відстеження історії таких змін. Отже, зсув від UTC є лише кількістю годин-хвилин-секунд вперед чи позаду меридіана. Часовий пояс набагато більше: історія з минулого, теперішнього і майбутніх змін до зсувів конкретного регіону. Хоча сьогодні два сусідні регіони можуть поділяти один і той же зсув від UTC, в минулому чи в майбутньому вони можуть відрізнятися залежно від різних примх чи логіки їх політиків.

Це означає, що сучасне відстеження часу, визначене політиками, мало пов’язане з географією. Наприклад, величезна країна Індія сьогодні має єдиний часовий пояс (зсув від UTC +05: 30). Тож сонячний полудень (сонце прямо над головою) - це години в різних місцях величезного субконтиненту. Політики Індії вирішили це допомогти об'єднати їх різноманітну демократію. В інших прикладах по всьому світу ми бачимо, як регіони використовують свій часовий пояс як символ міжнародних відносин, таких як відмінність від країни-сусіда, що обижається, або вибір тієї ж зони в якості сусіда, оскільки відносини відтають, як нещодавно спостерігалося в Північній Кореї, що змінюється відповідно до Південна Корея. Отже, сьогодні сонячний час є лише одним із кількох міркувань при відстеженні часу.


Про java.time

Java.time каркас вбудований в Java 8 і пізніших версій. Ці класи витісняти неприємні старі застарілі класи дати і часу , такі як java.util.Date, Calendar, і SimpleDateFormat.

Щоб дізнатись більше, див. Підручник Oracle . І шукайте в Stack Overflow багато прикладів та пояснень. Специфікація - JSR 310 .

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

Ви можете обмінювати об'єкти java.time безпосередньо з базою даних. Використовуйте драйвер JDBC, сумісний з JDBC 4.2 або новішою. Не потрібні рядки, не потрібні java.sql.*класи. Hibernate 5 та JPA 2.2 підтримують java.time .

Де отримати класи java.time?

Таблиця, яку бібліотеку java.time використовувати з якою версією Java або Android


Ви маєте на увазі значення зміщення різне в різний час в зоні? thx багато!
FredSuvn

1
@FredSuvn Це саме визначення переходу на літній час (літній час), півріччя одне зміщення, а півроку інше. І перехід на літній час не є єдиною причиною; інші аномалії викликають зміни зміщення для певних часових поясів. Наприклад, восени 2016 року Туреччина вирішила назавжди скоригувати свій відлік на годину далі до UTC ( +03:00). Політики часто вносять такі зміни, часто з невеликим попередженням. Це залишає людей, які намагаються оновити перелік визначень зон своїх баз даних `` tzdata ''.
Василь Бурке

1
Найкраща відповідь, яку я бачив на SO досить давно 😀 @FredSuvn, ви повинні прийняти відповідь, натиснувши the
вушну камеру

Для всіх, кого бентежить рівняння Часовий пояс = (Історія зсувів + Правила для аномалій) . Це не означає, що під час використання zone.getRules().getOffset(instant)вам потрібно додати будь-які додаткові аномалії до отриманого зміщення вручну, наприклад, літній час. Повернутий зсув - getOffset(instant)це вже точна кількість зсувів годин, хвилин і секунд від GMT на той момент часу. (Я завжди думав, що зсув - це просто географічний зсув, який описує, наскільки раніше / пізніше сонце сходить у цьому регіоні, але насправді враховує всі правила.)
andro

@anddero Ваш коментар надихнув мене видалити це рівняння та додати розділ про сонячний час проти політичного часу. Сподіваємось, це зараз читається чіткіше.
Василь Бурк

0

Залежно від вашої мети, ви зможете повністю обійти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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.