it-swarm.com.ru

JSR 310 :: System.currentTimeMillis () против Instant.toEpochMilli () :: TimeZone

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

Дано

1. Часовой пояс: GMT + 3

2. Следующий фрагмент кода:

import Java.time.*;

public class Main {        
    public static void main(String[] args) {
        System.out.println(LocalDateTime
            .now()
            .atZone(ZoneOffset.UTC)
            .toInstant()
            .toEpochMilli()
        );
        System.out.println(LocalDateTime
            .now()
            .atZone(ZoneOffset.of("+3"))
            .toInstant()
            .toEpochMilli()
        );
        System.out.println(System.currentTimeMillis());
    }
}

3. Результат:

1444158955508
1444148155508
1444148155508

4. JavaDoc для System.currentTimeMillis () , который сообщает, что возвращаемое значение будет разницей, измеренной в миллисекундах, между текущим временем и полуночью 1 января 1970 года по Гринвичу.

Итак, почему

  1. вывод LocalDateTime в GMT+3 такой же, как и для System.currentTimeMillis(), хотя в документах для System.currentTimeMillis() упоминается UTC?
  2. вывод LocalDateTime в UTC отличается от System.currentTimeMillis(), хотя в документах для System.currentTimeMillis() упоминается UTC?
17
szhem

И System.currentTimeMillis(), и Instant.toEpochMilli() возвращают количество миллисекунд с начала эпохи Unix. Это не «в» каком-либо конкретном часовом поясе, хотя эпоха Unix обычно выражается как «полночь 1 января 1970 года, UTC». Но момент - это всего лишь момент времени и тот же часовой пояс, в котором вы находитесь, но он будет отражать другое местное время.

Вывод LocalDateTime.atZone(UTC) отличается, потому что вы говорите: «Возьмите местную дату и время и конвертируйте их в момент как если бы он был в часовом поясе UTC » - даже если вы создали эту LocalDateTime, вы сделали это неявно в часовом поясе UTC + 3 ... вот почему это "неправильно".

LocalDateTime.now() принимает локальную дату и время в системном часовом поясе по умолчанию . Так, если ваш часовой пояс UTC + 3, текущий момент времени - 2015-10-06T16: 57: 00Z, тогда LocalDateTime.now() вернет .2015-10-06T19:57:00. Давайте назовем это localNow...

Таким образом, localNow.atZone(ZoneOffset.of("+3")) вернет ZonedDateTime, представляющий 2015-10-06T19: 57: 00 + 03 - другими словами, ту же местную дату/время, но «зная», что на 3 часа больше UTC ... поэтому toInstant() вернет Instant представляя 2015-10-06T16: 57: 00Z. Отлично - у нас все еще есть текущая дата/время.

Но localNow.atZone(ZoneOffset.UTC) вернет ZonedDateTime, представляющий 2015-10-06T19: 57: 00Z - другими словами, ту же локальную дату/время, но «думая», что она уже в UTC ... поэтому toInstant() вернет Instant, представляющую 2015-10 -06T19: 57: 00Z .. который вообще не является текущим временем (это через три часа).

31
Jon Skeet

Укороченная версия:

Нет способа вычислить LocalDateTime -> Instant, вам нужно указать часовой пояс . С часовым поясом вы получите ZonedDateTime и можете вычислить ZonedDateTime -> Instant

Instant == System.currentTimeMillis(), если часовой пояс ZonedDateTime равен системному часовому поясу по умолчанию.

Длинная версия:

LocalDateTime - время на ваших часах (плюс информация о дате). Этого недостаточно, если вы не сообщите нам, в каком часовом поясе вы находитесь. 13:00 в Токио - это не то же мгновение, что в 13:00 в Париже.

Как только вы добавите часовой пояс к вашему LocalDateTime, вы получите ZonedDateTime, и мы сможем узнать, в какой момент вы на самом деле находитесь. Например. Вы 13:00 в Токио или в Париже?

Чтобы получить правильный момент, часовой пояс ZonedDateTime должен быть правильным. Если в Токио 13:00, но вы утверждаете, что в Париже 13:00, вы получите неверный Мгновенный ответ.

LocalDateTime :

Он не может представлять момент на временной шкале без дополнительной информации, такой как смещение или часовой пояс.

ZonedDateTime :

Этот класс обрабатывает преобразование из локальной временной шкалы LocalDateTime в мгновенную временную шкалу Instant. Разница между двумя временными линиями - это смещение от UTC/Гринвич, представленное ZoneOffset.

Чтобы получить Instant вам нужно сначала преобразовать LocalDateTime в ZonedDateTime. Если вы сделали это правильно (указав правильный часовой пояс), ваш Instant согласуется с System.currentTimeMillis ().

System.currentTimeMillis () :

разница, измеренная в миллисекундах, между текущим временем и полуночью 1 января 1970 года по Гринвичу.

  1. выходные данные LocalDateTime в GMT + 3 такие же, как и в System.currentTimeMillis (), хотя в документах для System.currentTimeMillis () упоминается UTC?

Если ваш часовой пояс GMT + 3, то ZonedDateTime.toInstant () даст вам правильный момент и, следовательно, согласен с System.currentTimeMillis ()

  1. вывод LocalDateTime в UTC отличается от System.currentTimeMillis (), хотя в документах для System.currentTimeMillis () упоминается UTC?

Если ваш часовой пояс равен не UTC, то ZonedDateTime.toInstant () даст вам неверно Мгновенное действие.

0
Roland