Jak uzyskać milisekundy z LocalDateTime w Javie 8

285

Zastanawiam się, czy istnieje sposób, aby uzyskać aktualne milisekund od 1-1-1970 (epoki), stosując nowe LocalDate, LocalTimelub LocalDateTimeklasy Java 8.

Znany sposób jest poniżej:

long currentMilliseconds = new Date().getTime();

lub

long currentMilliseconds = System.currentTimeMillis();
George Siggouroglou
źródło
6
Co jest nie tak z System.currentTimeMillis()?
Dawood ibn Kareem
16
@DavidWallace Próbuje uzyskać datę, a nie bieżącą godzinę?
Anubian Noob
2
„... sposób na uzyskanie obecnych milisekund ...”
Dawood ibn Kareem
milisekund od 1–1970. Wędrowałem, czy istnieje metoda ich uzyskania przy użyciu nowych klas Java 8 LocalDate, LocalTime i LocalDateTime, ponieważ nie znalazłem żadnej.
George Siggouroglou
1
Rozumiem, że celem tych klas jest to, że jest to „skupione na człowieku” rozumienie czasu i currentTimeMillisbyłoby w tym kontekście nieistotne. Pomyśl Kalendarz + Zegar ścienny z naprawdę dobrą precyzją, bez obaw o strefy czasowe i lokalizację. Nie ma więc możliwości powrotu do „czasu UTC” z czasu lokalnego
Gus

Odpowiedzi:

325

Nie jestem do końca pewien, co rozumiesz przez „bieżące milisekundy”, ale założę, że jest to liczba milisekund od „epoki”, a mianowicie północy, 1 stycznia 1970 roku UTC.

Jeśli chcesz znaleźć liczbę milisekund od epoki teraz, a następnie użyć System.currentTimeMillis()jako Anubian Noob podkreślił . Jeśli tak, nie ma powodu, aby używać do tego nowych interfejsów API java.time.

Być może jednak masz już LocalDateTimegdzieś podobny obiekt i chcesz go przekształcić w milisekundy od epoki. Nie można tego zrobić bezpośrednio, ponieważ LocalDateTimerodzina obiektów nie ma pojęcia, w której strefie czasowej się znajdują. W związku z tym należy podać informacje o strefie czasowej, aby znaleźć czas w stosunku do epoki, która jest w UTC.

Załóżmy, że masz coś LocalDateTimetakiego:

LocalDateTime ldt = LocalDateTime.of(2014, 5, 29, 18, 41, 16);

Musisz zastosować informacje o strefie czasowej, podając ZonedDateTime. Jestem w tej samej strefie czasowej co Los Angeles, więc zrobiłbym coś takiego:

ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Los_Angeles"));

Oczywiście przyjmuje to założenia dotyczące strefy czasowej. Są też przypadki skrajne, które mogą wystąpić, na przykład, jeśli lokalny czas nazywa czas w pobliżu przejścia na czas letni (czas letni). Odłóżmy je na bok, ale należy pamiętać, że takie przypadki istnieją.

W każdym razie, jeśli możesz uzyskać poprawny ZonedDateTime, możesz przekonwertować to na liczbę milisekund od epoki, tak jak poniżej:

long millis = zdt.toInstant().toEpochMilli();
Znaki Stuarta
źródło
5
Zauważ, że ZonedDateTime już ma ten getEpochSecondsposób (poprzez domyślnie ChronoZonedDateTime ). Nie ma potrzeby Instant.
mabi
14
Jasne, jeśli wszystko czego potrzebujesz to sekundy, a nie milisekundy.
Stuart Marks
1
Ah dobrze, byłem nieprecyzyjny: ZonedDateTimema również Instantów getNanosposób, więc nie można po prostu wymienić instsię zdtna swoim przykładzie?
mabi
18
Unikaj matematyki na nanosach, używając zdt.get (ChronoField.MILLI_OF_SECOND). Unikaj wszystkich matematyki, używając zdt.toInstant (). ToEpochMilli ()
JodaStephen
1
W każdym razie, skoro zarówno Ty, jak i @walen skomentowaliście, postanowiłem teraz usunąć moje oryginalne wiadomości, aby uniknąć wprowadzających w błąd ludzi.
Per Lundberg
81

To, co robię, nie określam strefy czasowej,

System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("ctm " + System.currentTimeMillis());

daje

ldt 1424812121078 
ctm 1424812121281

Jak widać liczby są takie same, z wyjątkiem krótkiego czasu wykonania.

Na wypadek gdybyś nie lubił System.currentTimeMillis, użyj Instant.now().toEpochMilli()

Brian
źródło
3
Nie, Epoka odnosi się do UTC, ale aktualny czas jest pobierany ze strefy lokalnej.
Rafael Membrives
2
@ ChristofferHammarström ilość milisekund, które minęły od epoki, jest faktem niezależnym od strefy czasowej. To ta sama liczba milisekund, bez względu na porę dnia, którą to nazwiesz. Oba wyniki są różne, ponieważ maszyna Briana zajęła 203 milisekundy na wykonanie drugiego polecenia.
Fletch
Czy można używać UTC, gdy użytkownik może znajdować się w innej strefie czasowej
GilbertS
2
@ GilbertS prawdopodobnie nigdy nie powinieneś używać dokładnie tego kodu, używaj API zgodnie z przeznaczeniem. Data i czas powinny zawsze być UTC, jeśli są przechowywane na komputerze lub przesyłane do innego użytkownika. Zwykle powinien być prezentowany użytkownikowi jako lokalna data i godzina przy użyciu własnych ustawień strefy czasowej.
brian
20

Aby uniknąć ZoneId, możesz:

LocalDateTime date = LocalDateTime.of(1970, 1, 1, 0, 0);

System.out.println("Initial Epoch (TimeInMillis): " + date.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());

Otrzymanie 0 jako wartości, właśnie tak!

Dani
źródło
8
ZoneOffset.ofTotalSeconds(0)jest taki sam jakZoneOffset.UTC
Anton Novopashin
1
Tak, to byłem entuzjastycznie nastawiony do komentarza @ AntonNovopashin. Ponieważ potrzebujesz UTC, nic ci nie jest (możesz wspomnieć o tym w odpowiedzi). BTW ZoneOffsetjest podklasą ZoneId, więc nie powiedziałbym, że jej unikałeś, ale dopóki jesteś szczęśliwy ...
Ole VV
Mój pierwszy komentarz był nieco ostry, ale nie miał być obraźliwy. Obraziłeś się. Przepraszam. Usunąłem to. Pozwólcie, że zapytam na odwrót: jaki może być nasz powód, dla którego chcemy tego unikać ZoneId?
Ole VV,
@ OleV.V Czy korzystanie z UTC jest w porządku? Jest nie tylko dla osób żyjących w strefie czasowej UTC.
GilbertS
1
@GilbertS Nie sądzę, aby ktokolwiek mieszkał w strefie czasowej UTC. Zalecane jest stosowanie UTC dla czasów używanych w różnych strefach czasowych. Zobacz na przykład Java Best Practice w zakresie manipulacji / przechowywania danych dla zróżnicowanych geograficznie użytkowników . A może nie zrozumiałem twojego pytania?
Ole VV
15

Od wersji Java 8 możesz dzwonić java.time.Instant.toEpochMilli().

Na przykład połączenie

final long currentTimeJava8 = Instant.now().toEpochMilli();

daje takie same wyniki jak

final long currentTimeJava1 = System.currentTimeMillis();
Marteng
źródło
1
„daje takie same wyniki jak”… ale wymaga więcej mocy procesora i znacznie bardziej stresuje moduł wyrzucający śmieci.
VasiliNovikov,
1
Chciałbym zobaczyć powyższe ilościowo (szczególnie w przypadku normalnego użytkowania - np. Nie w przypadku aplikacji krytycznych pod względem wydajności w czasie rzeczywistym ...)
Brian Agnew
11

Możesz java.sql.Timestamptakże użyć, aby uzyskać milisekundy.

LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);
Nalam
źródło
Ignorujesz kluczową potrzebę strefy czasowej. Nie polecam robić tego w ten sposób. Również Timestampklasa jest od dawna przestarzała i pełna problemów projektowych, więc wolałbym jej unikać, szczególnie gdy możemy korzystać z klas java.timepodobnych LocalDateTime.
Ole VV
@ OleV.V. Po prostu ciekawy problemów projektowych Timestamp, czy możesz podzielić się z tym jakimś artykułem? Pomaga mi to również uniknąć używania Timestampz mojego kodu. Dzięki!
Nalam
1
Krótko mówiąc, jest zaimplementowany jako podklasa, Dateale często nie można go traktować jako Date. Większość metod odziedziczonych po Datejednym konstruktorze jest przestarzała. Jego toStringmetoda wykorzystuje strefę czasową maszyny JVM, która myli wiele, ponieważ Timestampjest ona drukowana inaczej na różnych komputerach ( przykład ).
Ole VV,
Jest to idealne do testów jednostkowych. Po prostu zastąp terazLocalDate.of(year, month, day)
G_V
To powinna być zaakceptowana odpowiedź na obejście wartości „zawsze UTC”.
LeYAUable
9

Aby uzyskać bieżący czas w milisekundach (od epoki), użyj System.currentTimeMillis().

Anubian Noob
źródło
3

Jeśli masz zegar Java 8, możesz go użyć clock.millis()(chociaż zaleca się, clock.instant()aby uzyskać Instant Java 8, ponieważ jest dokładniejszy).

Dlaczego miałbyś używać zegara Java 8? Tak więc w swoim środowisku DI możesz utworzyć komponent Clock Bean:

@Bean
public Clock getClock() {
    return Clock.systemUTC();
}

a następnie w swoich testach możesz łatwo Kpić:

@MockBean private Clock clock;

lub możesz mieć inną fasolę:

@Bean
public Clock getClock() {
    return Clock.fixed(instant, zone);
}

co pomaga w testach, które niezmiernie potwierdzają daty i godziny.

JeeBee
źródło
1
  default LocalDateTime getDateFromLong(long timestamp) {
    try {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC);
    } catch (DateTimeException tdException) {
      //  throw new 
    }
}

default Long getLongFromDateTime(LocalDateTime dateTime) {
    return dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli();
}
Mohamed.Abdo
źródło
0

Dlaczego nikt nie wspomniał o metodzie LocalDateTime.toEpochSecond():

LocalDateTime localDateTime = ... // whatever e.g. LocalDateTime.now()
long time2epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);

Wydaje się to znacznie krótsze niż wiele sugerowanych odpowiedzi powyżej ...

maxxyme
źródło
tego szukałem. Ta zaakceptowana odpowiedź dała mi wolę.
Brill Pappin
Zaakceptuj jego dostępne tylko w API 26: {
Brill Pappin
1
Ponieważ daje to tylko sekundy. To dziwne, że nie ma toEpochMillimetody, biorąc pod uwagę fakt, że można określić nawet nanosekundy w LocalDateTime: istnieje metoda LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond).
izogfif