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

219

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

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

Date myDate = new Date(startDateLong)

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

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

Vihung
источник
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());
Holger
источник
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();
Abhijeet
источник
новая отметка времени (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));
Santhosh Hirekerur
источник
-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 ». Я не понимаю, что здесь не ясно?
Кетан Р