Как я могу создать Java 8 LocalDate из долгого времени эпохи в миллисекундах?


219

У меня есть внешний API, который возвращает мне даты как longs, представленные в миллисекундах с начала эпохи.

Со старым стилем Java API я бы просто сконструировал Dateиз него

Date myDate = new Date(startDateLong)

Что эквивалентно в Java 8's LocalDate/ LocalDateTimeclasses?

Я заинтересован в превращении момента времени , представленный longк LocalDateв моей текущей локальной временной зоне.


6
Ну, вы должны начать с выяснения, какой часовой пояс вас волнует. Значение «миллисекунды с начала эпохи» дает вам момент времени ... который может относиться к разным датам в разных часовых поясах. Имейте в виду, что на java.util.Dateсамом деле это никогда не было свидание, LocalDateа момент времени.
— Джон Скит

2
Проверьте этот вопрос: stackoverflow.com/questions/21242110/… , который охватывает преобразование java.util.DateвLocalDate
— hotzst

3
Примечание: эти вопросы и ответы также полезны для тех, кто пытается преобразовать File.lastModified()(эпоха миллис) в LocalDate(Time).
— Кевинарпе

Ответы:


404

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

LocalDate date =
    Instant.ofEpochMilli(longValue).atZone(ZoneId.systemDefault()).toLocalDate();

но имейте в виду, что даже часовой пояс системы может измениться, поэтому одно и то же longзначение может привести к разным результатам при последующих запусках даже на одном компьютере.

Кроме того, имейте в виду, что LocalDate, в отличие от java.util.Date, действительно представляет собой дату, а не дату и время.

В противном случае вы можете использовать LocalDateTime:

LocalDateTime date =
    LocalDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneId.systemDefault());

2
+1 от меня за более подробное объяснение. Кстати, даже несистемная зона может измениться (с помощью tzupdater-tool или jdk-change) и, следовательно, привести к различным результатам до и после.
— Мено Хохшильд

2
@Meno Hochschild: Я не фокусировался на жестко закодированных часовых поясах, а скорее сравнивал их с часовыми поясами, указанными пользователем, читая из файла конфигурации или переменных среды, где программист, естественно, предполагает, что они могут измениться. Закодированные часовые пояса действительно очень похожи на системные по умолчанию; программисту хочется думать, что они никогда не меняются ...
— Хольгер

2
@Demigod LocalDateTime.ofEpochSecond(…)требует фактического ZoneOffset, но ZoneId.systemDefault()возвращает ZoneId. ZoneIdМожно сопоставить с различными смещениями, в зависимости от момента времени , вы имеете в виду. Вот что LocalDateTime.ofInstantделает для вас, конвертируя указанное в ZoneIdсоответствии с предоставленным Instant.
— Хольгер

2
Эпоха определяется как UTC и поэтому должна быть независимой от часового пояса, поэтому ZoneId всегда должен быть UTC.
— PlexQ

2
@PlexQ Указанный часовой пояс относится не к эпохе, которая действительно независима от часового пояса, но к семантике результирующего LocalDateили LocalDateTime. Вы можете указать любой часовой пояс, который вы хотите, при условии, что он совместим с последующим использованием этих объектов результатов. Подумайте, что происходит, когда вы имеете дело с несколькими объектами, созданными разными методами. Типичные случаи использования для локальной даты или даты и времени включают часовой пояс системы по умолчанию, например, LocalDateTime.now()≈ LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault())…
— Хольгер

37

Вы можете начать с Instant.ofEpochMilli (long) :

LocalDate date =
  Instant.ofEpochMilli(startDateLong)
  .atZone(ZoneId.systemDefault())
  .toLocalDate();

5
+1 за явную информацию о часовом поясе. Если опущено, текущий часовой пояс JVM по умолчанию неявно применяется при определении даты. В любой момент времени дата меняется по всему миру в зависимости от часового пояса, поскольку на востоке наступает новый день.
— Базилик Бурк

12

Я думаю, что у меня есть лучший ответ.

new Timestamp(longEpochTime).toLocalDateTime();

новая отметка времени (ts) .toLocalDateTime (). toLocalDate ()
— Степан Яковенко

5
Я имею в виду - если вы не возражаете против импорта javal.sql.Timestamp, который, учитывая монолитную природу Java, я думаю, это хорошо, потому что это всего лишь часть JVM ... но чувствует себя немного вонючим, но мне все еще нравится это лучше, так как это признанная эпоха в основном в UTC.
— PlexQ

1
TimestampКласс плохо разработаны и давно устарели. В вашем коде будет использоваться настройка часового пояса JVM, но, поскольку этот параметр может быть изменен другой частью вашей программы или другой программой, запущенной в той же JVM, мы не можем быть полностью уверены, что это такое.
— Оле В.В.

1
Всегда лучше четко указать, какой часовой пояс используется. Использование старого java.sql.Timestamp имеет недостаток неявного применения системного часового пояса, что обычно вызывает путаницу среди разработчиков.
— Руслан

3

Часовые пояса и прочее в стороне, очень простая альтернатива new Date(startDateLong)могут бытьLocalDate.ofEpochDay(startDateLong / 86400000L)


6
Я думаю, что вы должны хотя бы объяснить, что означает 86400000L.
— БЕРУС

3
Я думал, что было очень легко заметить, что это количество миллисекунд в день.
— Майкл Пифель

7
Для некоторых это так, и я подумал, что только это имело бы смысл, но без пересчета того, сколько мс в день действительно есть, я не был бы уверен. Говоря сам за себя, я не знаю этот номер так хорошо, что автоматически знаю, что он обозначает.
— BAERUS

Обратите внимание, что принятый ответ действительно является лучшим ответом, он выглядит просто ошеломляюще. Моего простого взлома мне достаточно во многих случаях. Жаль, что java.timeне включает, DateTimeConstantsкак Йода.
— Майкл Пифель

2
java.util.concurrent.TimeUnit.MILLISECONDS.toDays(startDateLong)
— Вадим

1

замените now.getTime () вашим длинным значением.

//GET UTC time for current date
        Date now= new Date();
        //LocalDateTime utcDateTimeForCurrentDateTime = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDateTime();
        LocalDate localDate = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDate();
        DateTimeFormatter dTF2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        System.out.println(" formats as " + dTF2.format(utcDateTimeForCurrentDateTime));

-6

В конкретном случае, когда ваша отметка времени в секундах происходит от SQL или как-то связана с SQL, вы можете получить ее следующим образом:

long startDateLong = <...>

LocalDate theDate = new java.sql.Date(startDateLong).toLocalDate();

2
На самом деле это не имеет большого отношения к
— Ketan R

@KetanR, я не согласен. Вопрос «как получить LocalDateиз epoch-millis», и я покажу, как, используя java.sql.Dateдля краткости. Этот подход имеет смысл в коде, который уже имеет дело с JDBC в некотором объеме, и он работает просто отлично. Если вы все еще не уверены, объясните, как это не связано с первоначальным вопросом.
— М. Прохоров

2
Если вы читаете вопрос, он говорит: «Внешний API, который возвращает мне даты как длинные», и вы объясняете, как можно выполнить это преобразование, если вы получаете длинную дату из SQL. Ваш ответ действительно объясняет очень конкретный случай преобразования даты, но он не имеет никакого отношения к вопросу, который был задан под редакцией. Однако ваше объяснение может быть верным ответом на некоторые другие связанные вопросы.
— Кетан Р

@KetanR, если кто-то получает длинную дату из SQL, я бы посоветовал изменить его схему, чтобы он больше не получал даты в такой форме. Однако, если кто-то получает даты в виде миллисекундных меток из другого места (внешний API) и сразу использует эти даты для выполнения запросов JDBC, тогда java.sql.Dateподход является одним из самых коротких из доступных, с точки зрения кода, и я бы сказал, что это не так уж и полезно идти Instantсо всеми промежуточными временными объектами, когда конечный результат одинаков.
— М. Прохоров

2
Как я уже сказал, и из вашего последнего объяснения видно, что ваш ответ верен, но не для рассматриваемого вопроса. Вопрос говорит: «Я заинтересован в преобразовании момента времени, представленного long, в LocalDate в моем текущем местном часовом поясе. «Ваш ответ говорит:« получать даты в виде миллисекундных меток и немедленно использовать эти даты для выполнения запросов JDBC ». Я не понимаю, что здесь не ясно?
— Кетан Р
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.