Вызов toInstant().toEpochMilli()
, как предложено в комментарии @JB Nizet , является правильным ответом, но есть небольшая и хитрая деталь об использовании местных дат, о которой вы должны знать.
Но перед этим еще несколько мелких деталей:
- Вместо
ZoneId.of("GMT")
можно использовать встроенную константу ZoneOffset.UTC
. Они эквивалентны, но нет необходимости создавать дополнительные избыточные объекты, если API уже предоставляет объект, который делает то же самое.
- Вместо того, чтобы вызывать
LocalDateTime.now()
, а затем .toLocalDate()
, вы можете напрямую вызвать LocalDate.now()
— они эквивалентны.
Теперь сложные детали: когда вы вызываете метод now()
(либо для LocalDateTime
, либо для LocalDate
), он использует часовой пояс JVM по умолчанию для получения значений текущей даты, и это значение может отличаться в зависимости от часового пояса, настроенного в JVM.
В JVM, которую я использую, часовой пояс по умолчанию — America/Sao_Paulo
, а местное время — 09:37. Таким образом, LocalDate.now()
возвращает 2017-08-22
(22th августа 2017 г.).
Но если я изменю часовой пояс по умолчанию на Pacific/Kiritimati
, он вернет 2017-08-23
. Это потому, что в Киритимати сейчас уже 23го августа 2017 года (и местное время там, на момент, когда я это пишу, 02:37< /сильный>).
Итак, если я запускаю этот код, когда часовой пояс по умолчанию равен Pacific/Kiritimati
:
LocalDate dtNow = LocalDate.now(); // 2017-08-23
System.out.println(dtNow.atStartOfDay(ZoneOffset.UTC).toInstant().toEpochMilli());
Результат:
1503446400000
Что эквивалентно полуночи 23th августа 2017 года по всемирному координированному времени.
Если я запущу тот же код, когда часовой пояс по умолчанию America/Sao_Paulo
, результат будет таким:
1503360000000
Что эквивалентно полуночи 22th августа 2017 года по всемирному координированному времени.
Использование now()
делает ваш код зависимым от часового пояса JVM по умолчанию. И эта конфигурация может быть изменена без предварительного уведомления, даже во время выполнения, что приведет к тому, что ваш код будет возвращать разные результаты при таких изменениях.
И вам не нужен такой крайний случай (например, кто-то неправильно настроил JVM на «очень дальний» часовой пояс). В моем случае, например, в часовом поясе America/Sao_Paulo
, если я запущу код в 23:00, LocalDate
вернет 22августа, но текущая дата в формате UTC уже будет 23августа. Это связано с тем, что 23:00 в Сан-Паулу совпадают с 2:00 следующего дня по UTC:
// August 22th 2017, at 11 PM in Sao Paulo
ZonedDateTime z = ZonedDateTime.of(2017, 8, 22, 23, 0, 0, 0, ZoneId.of("America/Sao_Paulo"));
System.out.println(z); // 2017-08-22T23:00-03:00[America/Sao_Paulo]
System.out.println(z.toInstant()); // 2017-08-23T02:00:00Z (in UTC is already August 23th)
Таким образом, использование LocalDate.now()
не является гарантией того, что у меня всегда будет текущая дата в формате UTC.
Если вам нужна текущая дата в формате UTC (независимо от часового пояса JVM по умолчанию) и установите время на полночь, лучше использовать ZonedDateTime
:
// current date in UTC, no matter what the JVM default timezone is
ZonedDateTime zdtNow = ZonedDateTime.now(ZoneOffset.UTC);
// set time to midnight and get the epochMilli
System.out.println(zdtNow.with(LocalTime.MIDNIGHT).toInstant().toEpochMilli());
Результат:
1503360000000
Что эквивалентно полуночи 22th августа 2017 года по всемирному координированному времени.
Другой альтернативой является передача часового пояса в LocalDate.now
, чтобы он мог получить правильные значения для текущей даты в указанной зоне:
// current date in UTC, no matter what the JVM default timezone is
LocalDate dtNowUtc = LocalDate.now(ZoneOffset.UTC);
// set time to midnight and get the epochMilli
System.out.println(dtNow.atStartOfDay(ZoneOffset.UTC).toInstant().toEpochMilli());
person
Community
schedule
22.08.2017
LocalDate
илиLocalDateTime
? Вы спрашиваете LocalDate и приводите пример дляLocalDateTime
. - person Jens   schedule 22.08.2017