Есть ли способ преобразовать ZoneId в ZoneOffset в java 8?


89

У меня есть вторая эпоха и zoneId по методу 1. Его можно преобразовать в LocalDateTime с помощью system default zoneId, но я не могу найти способ преобразовать эпоху в LocalDateTime с помощью метода 2, потому что нет. 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
Может быть Scala, но здесь это не очень важно
donatas M

1
Я подробно обсудил теорию java.timeздесь: stackoverflow.com/a/56508200/145989
Ондра Жижка

Ответы:


113

Вот как вы можете получить ZoneOffsetот ZoneId:

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

NB: ZoneIdможет иметь разное смещение в зависимости от момента времени и истории конкретного места. Таким образом, выбор разных мгновений приведет к разным смещениям.

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


Это дает неверное значение, если текущий момент находится в DST, но на момент расчета он был без DST
msangel

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

Я проверил это, и он работает в зависимости от других условий. Обновленный ответ с этим.
msangel

43

Нет однозначного сопоставления. ZoneId определяет географический экстент, в котором с течением времени используется набор различных ZoneOffset. Если часовой пояс использует летнее время, его ZoneOffset будет другим летом и зимой.

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

Таким образом, вы можете найти ZoneOffset для ZoneId только в конкретном Instant.

См. Также https://en.wikipedia.org/wiki/Tz_database.


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

35

tl; dr

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 . Одно и то же количество наносекунд с начала эпохи в любом случае, как ZonedDateTimeили какInstant .

Заданные секунды с начала эпохи

Если вам задано количество секунд с начала эпохи, а эпоха является первым моментом 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 Tutorial . И поищите в 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Для меня переход с помощью имеет смысл - ваша эпохальная секунда фактически является другим представлением Instant, поэтому конвертируйте в, 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

2

Следующее возвращает количество времени в миллисекундах, которое нужно добавить к UTC, чтобы получить стандартное время в этом часовом поясе:

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

0

У меня есть секунда эпохи и идентификатор зоны. Есть ли способ преобразовать ZoneId в ZoneOffset в java 8?

  1. Получить ZonedDateTimeиз второй эпохи и идентификатора зоны
  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.