Jak mogę utworzyć lokalną datę Java 8 z długiego okresu Epoki w milisekundach?

218

Mam zewnętrzny interfejs API, który zwraca mi daty jako longs, reprezentowane jako milisekundy od początku Epoki.

W starym stylu Java API, po prostu konstruowałbym Datez niego

Date myDate = new Date(startDateLong)

Jaki jest odpowiednik w Javie 8 LocalDate/ LocalDateTimeklasach?

Jestem zainteresowany przekształcając punkt w czasie, reprezentowana przez longDo LocalDatew moim obecnym lokalnej strefy czasowej.

Vihung
źródło
6
Musisz zacząć od określenia strefy czasowej, na której Ci zależy. Wartość „milisekund od epoki” daje ci moment w czasie ... który może odnosić się do różnych dat w różnych strefach czasowych. Pamiętaj, że java.util.Datetak naprawdę nigdy nie była to randka LocalDate- to była chwila.
Jon Skeet
2
Sprawdź to pytanie: stackoverflow.com/questions/21242110/... , który obejmuje konwersję java.util.DatedoLocalDate
hotzst
3
Uwaga: te pytania i odpowiedzi są również cenne dla osób próbujących przekonwertować File.lastModified()(epoka millis) na LocalDate(Time).
kevinarpe

Odpowiedzi:

403

Jeśli masz milisekundy od Epoki i chcesz przekonwertować je na lokalną datę przy użyciu bieżącej lokalnej strefy czasowej, możesz użyć

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

ale należy pamiętać, że nawet domyślna strefa czasowa systemu może ulec zmianie, dlatego ta sama longwartość może powodować różne wyniki w kolejnych uruchomieniach, nawet na tym samym komputerze.

Ponadto należy pamiętać, że LocalDatew przeciwieństwie do tego java.util.Date, naprawdę reprezentuje datę, a nie datę i godzinę.

W przeciwnym razie możesz użyć LocalDateTime:

LocalDateTime date =
    LocalDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneId.systemDefault());
Holger
źródło
2
+1 ode mnie za bardziej szczegółowe wyjaśnienie. Nawiasem mówiąc, nawet strefa niesystemowa może się zmieniać (za pomocą narzędzia tzupdater lub zmiany jdk), a tym samym dawać różne wyniki przed i po.
Meno Hochschild,
2
@Meno Hochschild: Nie skupiałem się na zakodowanych strefach czasowych, ale raczej na porównaniu ze strefami czasowymi określonymi przez użytkownika, odczytanymi z pliku konfiguracyjnego lub zmiennych środowiskowych, w których programista naturalnie zakłada, że ​​może się to zmienić. Zakodowane strefy czasowe są rzeczywiście bardzo podobne do domyślnych systemów; programista ma ochotę myśleć, że nigdy się nie zmieniają…
Holger
2
@Demigod LocalDateTime.ofEpochSecond(…)wymaga faktycznego ZoneOffset, ale ZoneId.systemDefault()zwraca a ZoneId. ZoneIdMożna mapować do różnych przesunięć, w zależności od punktu czasu masz na myśli. To LocalDateTime.ofInstantrobi dla ciebie, konwertując określone ZoneIdzgodnie z podanymi Instant.
Holger
2
Epoka jest zdefiniowana jako UTC i dlatego powinna być niezależna od strefy czasowej, więc ZoneId powinien zawsze być UTC.
PlexQ
2
@PlexQ Określona strefa czasowa nie jest istotna dla Epoki, która faktycznie jest niezależna od strefy czasowej, ale dla semantyki wynikowego LocalDatelub LocalDateTime. Możesz określić dowolną strefę czasową, o ile jest to zgodne z późniejszym użyciem tych obiektów wynikowych. Pomyśl o tym, co dzieje się, gdy masz do czynienia z wieloma obiektami utworzonymi różnymi metodami. Typowe przypadki użycia dla lokalnej daty lub czasu danych obejmują domyślną strefę czasową systemu, np. LocalDateTime.now()LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault())
Holger
37

Możesz zacząć od Instant.ofEpochMilli (długi) :

LocalDate date =
  Instant.ofEpochMilli(startDateLong)
  .atZone(ZoneId.systemDefault())
  .toLocalDate();
Meno Hochschild
źródło
5
+1 za wyraźne określenie strefy czasowej. Jeśli zostanie pominięty, bieżąca domyślna strefa czasowa maszyny JVM jest domyślnie stosowana przy ustalaniu daty. W danym momencie data zmienia się na całym świecie w zależności od strefy czasowej, gdy nowy dzień zaczyna świtać wcześniej na wschodzie.
Basil Bourque,
12

Myślę, że mam lepszą odpowiedź.

new Timestamp(longEpochTime).toLocalDateTime();
Abhijeet
źródło
new Timestamp (ts) .toLocalDateTime (). toLocalDate ()
Stepan Yakovenko
5
Mam na myśli - jeśli nie masz nic przeciwko importowaniu javal.sql.Testestamp, co, biorąc pod uwagę monolityczną naturę Javy, myślę, że jest w porządku, ponieważ jest to tylko część JVM ... ale czuje się trochę śmierdząco, ale nadal podoba mi się to, ponieważ uznana epoka jest zasadniczo w UTC.
PlexQ
1
TimestampKlasa jest źle zaprojektowana i długo nieaktualne. Twój kod będzie używał ustawienia strefy czasowej JVM, ale ponieważ to ustawienie może zostać zmienione przez inną część Twojego programu lub inny program działający w tej samej JVM, nie możemy być całkiem pewni, co to jest.
Ole VV
1
Zawsze lepiej jest wyraźnie określić, która strefa czasowa jest używana. Używanie starego java.sql.Timestamp ma tę wadę, że systemowa strefa czasowa jest stosowana niejawnie, co zwykle powoduje zamieszanie wśród programistów.
Ruslan
3

Poza strefami czasowymi i innymi rzeczami, new Date(startDateLong)może to być bardzo prosta alternatywaLocalDate.ofEpochDay(startDateLong / 86400000L)

Michael Piefel
źródło
6
Myślę, że powinieneś przynajmniej wyjaśnić, co oznacza 86400000L.
BAERUS
3
Pomyślałem, że bardzo łatwo jest zauważyć, że jest to liczba milisekund dziennie.
Michael Piefel
7
Dla niektórych tak jest i doszedłem do wniosku, że tylko to miałoby sens, ale bez przeliczenia, ile ms naprawdę ma dziennie, nie byłbym pewien. Mówiąc sam za siebie, nie znam tego numeru tak dobrze, że automatycznie wiem, co to znaczy.
BAERUS
Zauważ też, że zaakceptowana odpowiedź jest naprawdę najlepszą odpowiedzią, po prostu wygląda przytłaczająco. Mój prosty hack wystarczy mi w wielu przypadkach. Szkoda, że java.timenie obejmuje to DateTimeConstantstak jak Joda.
Michael Piefel
2
java.util.concurrent.TimeUnit.MILLISECONDS.toDays(startDateLong)
Vadzim
1

zamień now.getTime () na swoją długą wartość.

//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
źródło
-6

W konkretnym przypadku, gdy znacznik czasu twojej epoki pochodzi z SQL lub jest w jakiś sposób związany z SQL, możesz go uzyskać w następujący sposób:

long startDateLong = <...>

LocalDate theDate = new java.sql.Date(startDateLong).toLocalDate();
M. Prochorow
źródło
2
To tak naprawdę nie ma wiele wspólnego z zadanym pytaniem
Ketan R
@KetanR, nie zgadzam się. Pytanie brzmi „jak uzyskać LocalDateod epoch-millis”, a ja pokazuję, jak to zrobić za pomocą java.sql.Dateskrótu. To podejście ma sens w kodzie, który już w pewnym stopniu zajmuje się JDBC, i działa dobrze. Jeśli nadal nie jesteś przekonany, wyjaśnij, w jaki sposób nie ma to związku z początkowym pytaniem.
M. Prochorow,
2
Jeśli przeczytasz pytanie, jest napisane: „zewnętrzny interfejs API, który zwraca mi tak długie daty” i wyjaśniasz, w jaki sposób można wykonać tę konwersję, jeśli otrzymujesz długą datę z SQL. Twoja odpowiedź wyjaśnia bardzo konkretny przypadek konwersji daty, ale nie jest tak naprawdę istotna dla pytania, które zostało zadane. Twoje wyjaśnienie może być jednak prawidłową odpowiedzią na inne powiązane pytanie.
Ketan R
@KetanR, jeśli ktoś otrzyma długą datę z SQL, radzę zmienić jego schemat, aby nie otrzymywał już dat w takiej formie. Jeśli jednak ktoś odbiera daty w postaci milisekundowych znaczników czasu z innego miejsca (zewnętrzny interfejs API) i natychmiast wykorzystuje je do tworzenia zapytań JDBC, to java.sql.Datepodejście należy do najkrótszych dostępnych, pod względem kodu, i powiedziałbym, że nie jest to aż tak przydatne iść Instantze wszystkimi pośrednimi obiektami czasowymi, gdy wynik końcowy jest taki sam.
M. Prochorow
2
Jak już powiedziałem i jest oczywiste z twojego ostatniego wyjaśnienia, twoja odpowiedź jest poprawna, ale nie na pytanie, o które chodzi. Pytanie mówi: „Jestem zainteresowany przekształceniem punktu czasu reprezentowanego przez długość na datę lokalną w mojej bieżącej lokalnej strefie czasowej. „twoja odpowiedź mówi:„ odbieraj daty jako millis-timestamps i natychmiast używaj tych dat do tworzenia zapytań JDBC ”. Nie rozumiem, co tutaj nie jest jasne?
Ketan R