Як я можу створити Java 8 LocalDate за тривалий час в епохи за кілька мілісекунд?


218

У мене є зовнішній API, який повертає мені дати як longs, представлені у мілісекундах від початку Епохи.

За допомогою старого стилю Java API, я просто побудую Dateз нього

Date myDate = new Date(startDateLong)

Який еквівалент у Java 8 LocalDate/ LocalDateTimeкласах?

Мене цікавить перетворення моменту часу, представленого символом longa, LocalDateу моєму місцевому часовому поясі.


6
Ну, для початку вам слід розібратися, про який часовий пояс ви дбаєте. Значення "мілісекунд з епохи" дає вам мить у часі ..., яка може стосуватися різних дат у різних часових поясах. Майте на увазі, що java.util.Dateніколи насправді побачення не було таким, яким воно LocalDateє - це було і мить у часі.
Джон Скіт

2
Перевірте це питання: stackoverflow.com/questions/21242110/… , яке охоплює перетворення java.util.DateнаLocalDate
hotzst

3
Примітка. Ця запитання також цінна для тих, хто намагається перетворити File.lastModified()(епохи мільйони) в LocalDate(Time).
kevinarpe

Відповіді:


403

Якщо у вас є мілісекунди з часів епохи і хочете перетворити їх на локальну дату, використовуючи поточний локальний часовий пояс, ви можете використовувати

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()повертає a 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())
Holger

37

Ви можете почати з Instant.ofEpochMilli (довгий) :

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

5
+1 за те, що явно стосується часового поясу. У разі відсутності поточного часового поясу за замовчуванням JVM неявно застосовується при визначенні дати. Для будь-якого моменту дата змінюється в усьому світі за часовим поясом, як світанок нового дня раніше на сході.
Василь Бурк

12

Я думаю, я маю кращу відповідь.

new Timestamp(longEpochTime).toLocalDateTime();

нова мітка часу (ц) .toLocalDateTime (). toLocalDate ()
Степан Яковенко

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

1
TimestampКлас погано розроблені і давно застаріли. Ваш код буде використовувати налаштування часового поясу JVM, але оскільки це налаштування можна змінити іншою частиною вашої програми або іншою програмою, що працює в тому ж JVM, ми не можемо бути впевнені, що це таке.
Оле ВВ

1
Завжди краще бути чітким щодо того, який часовий пояс використовується. Використання старого java.sql.Timestamp має недолік того, що системний часовий пояс застосовується неявно, що зазвичай викликає плутанину серед розробників.
Руслан

3

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


6
Я думаю, ви повинні хоча б пояснити, що означає 86400000L.
BAERUS

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. У вашій відповіді пояснюється дуже конкретний випадок перетворення дати, але це не дуже важливо для запитання, яке було задано редакцією. Хоча ваше пояснення може бути вагомою відповіддю на якийсь інший пов'язаний питання.
Ketan R

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

2
Як я вже говорив, і це видно з останнього пояснення, ваша відповідь правильна, але не на відповідне питання. Питання каже: "Мені цікаво перетворити моменти часу, представлені довгим, в LocalDate в моєму місцевому часовому поясі. "Ваша відповідь повідомляє:" отримуйте дати як мільйонні часові позначки, і негайно використовуйте ці дати для здійснення запитів JDBC ". Я не розумію, що тут не зрозуміло?
Ketan R
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.