Чи є спосіб перетворити ZoneId на ZoneOffset в Java 8?


85

У мене є секунда епохи і zoneId за методом 1. Його можна перетворити в LocalDateTime за допомогою системного типового zoneId, але я не знаходжу способу перетворити епоху другої в LocalDateTime методом method2, тому що немає. ZoneOffset.systemDefaultЯ думаю, що це неясно.

import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset}

val epochSecond = System.currentTimeMillis() / 1000

LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), ZoneId.systemDefault())//method1
LocalDateTime.ofEpochSecond(epochSecond, 0, ZoneOffset.MAX)//method2

Яку мову / діалект ви використовуєте для масового імпорту import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset}? Це unexpected tokenдля мене в Java 11.
anddero

1
Може бути Скалою, але це насправді тут не дуже важливо
донатас M

1
Я довго обговорював теорію позаду java.time: stackoverflow.com/a/56508200/145989
Ondra Žižka,

Відповіді:


109

Ось як ви можете отримати ZoneOffsetз ZoneId:

Instant instant = Instant.now(); //can be LocalDateTime
ZoneId systemZone = ZoneId.systemDefault(); // my timezone
ZoneOffset currentOffsetForMyZone = systemZone.getRules().getOffset(instant);

Примітка: ZoneIdможе мати різний зсув залежно від моменту часу та історії конкретного місця. Отже, вибір різних екземплярів призведе до різного зміщення.

NB2: ZoneId.of()може повернути ZoneOffsetзамість того, ZoneIdякщо UTC+3/ GMT+2/ etc передано на відміну від часового поясу типу Africa/Cairo. Отже, якщо будуть передані компенсації UTC / GMT, тоді історична / географічна / перехід на літній час Instantне буде врахована - ви просто будете працювати із зазначеним зміщенням.


Це дає неправильне значення, якщо поточний момент знаходиться в
літньому / літньому дні

@msangel, ти можеш це ще раз перевірити? Можливо, ви використовуєте ZoneId.systemDefault()у своєму коді, і він повертає різні часові пояси на різних машинах?
Станіслав Башкирцев

Я перевірив це, і це працює залежно від іншої умови. Оновлена ​​відповідь із цим.
msangel

43

Немає індивідуального відображення. Ідентифікатор ZoneId визначає географічний ступінь використання набору різних ZoneOffsets з часом. Якщо в часовому поясі використовується перехід на літній час, його ZoneOffset буде відрізнятися влітку та взимку.

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

Таким чином, ви можете знайти ZoneOffset для ZoneId лише на певному миттєвому пошуку.

Див. Також https://en.wikipedia.org/wiki/Tz_database


10
Я це знаю, але як це робиться? Якщо я знаю LocaDate і маю ZoneId, як перетворити його на ZoneOffset. Мій варіант використання - це рядок, який містить час і пояс. Я хочу проаналізувати рядок на OffsetTime, не втрачаючи інформацію про зону.
Kai Moritz

33

tl; д-р

ZonedDateTime.now( 
    ZoneId.of( "America/Montreal" ) 
)

… Поточного часового поясу за замовчуванням…

ZonedDateTime.now( 
    ZoneId.systemDefault() 
)

Деталі

Відповідь Станіслав Bshkyrtsev правильно і безпосередньо відповідає на ваше запитання.

Але тут є й більші проблеми, як пропонується у відповіді Джона Скіта .

LocalDateTime

Я не знаходжу способу перетворити епоху другої в LocalDateTime

LocalDateTimeнавмисно не має поняття часового поясу чи зсуву від UTC. Напевно, що ти хочеш. Local…Чи означає будь-яку місцевість, а не якийсь - небудь однієї конкретної місцевості. Цей клас не представляє моменту, а лише потенційні моменти в діапазоні приблизно 26-27 годин (діапазон часових поясів по всьому світу).

Instant

Не потрібно починати з епохальних секунд, якщо ви намагаєтесь визначити поточний час. Отримайте струм Instant. InstantКлас являє собою момент на часовій шкалі в форматі UTC з дозволом наносекунд (до дев'яти (9) цифр десяткового дробу).

Instant instant = Instant.now();

Всередині цього Instant- відлік наносекунд - від епохи. Але нас насправді не хвилює.

ZonedDateTime

Якщо ви хочете побачити цей момент крізь призму годинника настінного часу певної області, застосуйте a, ZoneIdщоб отримати a ZonedDateTime.

ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdt = instant.atZone( z );

Як ярлик можна зробити безпосередньо до ZonedDateTime.

ZonedDateTime zdt = ZonedDateTime.now( z );  

A ZonedDateTimeмає Instantвсередині нього. Телефонуйте, zdt.toInstant()щоб отримати той самий момент часу, що і базове значення в UTC . Стільки ж наносекунд з епохи в будь-який спосіб, як a, ZonedDateTimeтак і aInstant .

Дано секунди з епохи

Якщо вам дається кількість секунд з часу епохи, і епоха - це перший момент 1970 року в UTC ( 1970-01-01T00:00:00Z), тоді подайте це число до Instant.

long secondsSinceEpoch = 1_484_063_246L ;
Instant instant = Instant.ofEpochSecond( secondsSinceEpoch ) ;

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


Про 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.*класи.

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

Проект ThreeTen-Extra розширює java.time додатковими класами. Цей проект є полігоном для можливих майбутніх доповнень до java.time. Ви можете знайти деякі корисні класи тут , такі як Interval, YearWeek, YearQuarter, і більш .


10

Як сказано в документації , "це в першу чергу призначено для низькорівневих перетворень, а не для загального використання програм".

Перехід через Instantмене має цілком сенс - ваша секунда епохи - це фактично інше подання an Instant, тому перетворіть на an, Instantа потім перетворіть це в певний часовий пояс.


9

Сподіваюсь, перші два рядки мого рішення нижче є корисними. Моя проблема полягала в тому, що у мене був LocalDateTimeі назва часового поясу, і мені потрібен був, instantщоб я міг побудувати java.util.Date, тому що цього хотів MongoDB. Мій код - Scala, але тут він настільки близький до Java, що, думаю, не повинно виникнути проблем із його розумінням:

val zid = ZoneId.of(tzName)                                // "America/Los_Angeles"
val zo: ZoneOffset = zid.getRules.getOffset(localDateTime) // ⇒ -07:00
                                         // 2017-03-16T18:03

val odt = OffsetDateTime.of(localDateTime, zo) // ⇒ 2017-03-16T18:03:00-07:00
val instant = odt.toInstant                    // ⇒ 2017-03-17T01:03:00Z
val issued = Date.from(instant)

1
Я розмістив цю відповідь тут, оскільки це була сторінка, яка з’явилася, коли я шукав спосіб зробити те, що я врешті з’ясував.
gknauth

1

Далі повертається кількість часу в мілісекундах, яке потрібно додати до UTC, щоб отримати стандартний час у цьому часовому поясі:

TimeZone.getTimeZone(ZoneId.of("Europe/Amsterdam")).getRawOffset()

0

У мене є епоха друга і зона Ідентифікатор. Чи є спосіб перетворити ZoneId на ZoneOffset в Java 8?

  1. Отримати ZonedDateTimeвід epoch second та Zone Id
  2. Отримати ZoneOffsetвідZonedDateTime

Демо:

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        // Get ZonedDateTime from epoch second and Zone Id
        ZonedDateTime zdt = Instant.ofEpochSecond(1597615462L).atZone(ZoneId.of("Europe/London"));

        // Get ZoneOffset from ZonedDateTime
        ZoneOffset offset = zdt.getOffset();

        System.out.println(offset);
    }
}

Вихід:

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