JSR 310:: System.currentTimeMillis() vs 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 UTC.

Итак, почему

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

Ответ 1

Оба 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...

So localNow.atZone(ZoneOffset.of("+3")) вернет a 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.., который не является текущим временем (он через три часа).

Ответ 2

Краткая версия:

LocalDateTime → Instant вычислить LocalDateTime → Instant, вам нужно указать часовой пояс. С ZonedDateTime вы получаете 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/Greenwich, представленное ZoneOffset.

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

System.currentTimeMillis():

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

  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() даст вам неправильный Мгновенный.