Jak wyodrębnić epokę z LocalDate i LocalDateTime?

102

Jak wyodrębnić wartość epoki Longz wystąpień LocalDateTimelub LocalDate? Wypróbowałem następujące, ale daje mi to inne wyniki:

LocalDateTime time = LocalDateTime.parse("04.02.2014  19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy  HH:mm:ss"));
System.out.println(time.getLong(ChronoField.SECOND_OF_DAY)); // gives 71461
System.out.println(time.getLong(ChronoField.EPOCH_DAY)); // gives 16105

To, czego chcę, to po prostu wartość 1391539861lokalnej daty i godziny "04.02.2014 19:51:01". Moja strefa Europe/Osloczasowa to UTC + 1 z czasem letnim.

Vadim Kotov
źródło
Proszę wyjaśnić swój oczekiwany numer 1396468261. Otrzymuję bez korekty strefy czasowej: 1391543461 (zobacz edycję w mojej odpowiedzi). 57 dni różnicy!
Meno Hochschild
@MenoHochschild Zaktualizowałem moje pytanie informacjami o strefie czasowej i poprawiłem rzeczywistą wartość z GTM na czas lokalny. Czy jest łatwiejszy sposób na uzyskanie LocalDateTimeinnej epoki niż ręczne jej obliczenie?
Wracając z mojej przerwy, zobacz moją aktualizację.
Meno Hochschild

Odpowiedzi:

147

Klasy LocalDatei LocalDateTimenie zawierają informacji o strefie czasowej lub przesunięciu czasowym , a sekundy od epoki byłyby niejednoznaczne bez tej informacji. Jednak obiekty mają kilka metod przekształcania ich w obiekty daty / godziny ze strefami czasowymi przez przekazanie ZoneIdinstancji.

LocalDate

LocalDate date = ...;
ZoneId zoneId = ZoneId.systemDefault(); // or: ZoneId.of("Europe/Oslo");
long epoch = date.atStartOfDay(zoneId).toEpochSecond();

LocalDateTime

LocalDateTime time = ...;
ZoneId zoneId = ZoneId.systemDefault(); // or: ZoneId.of("Europe/Oslo");
long epoch = time.atZone(zoneId).toEpochSecond();
nosid
źródło
2
Czy można uniknąć używania ZoneId lub używać z dostosowaną, stałą instancją ZoneId (+0, co oznacza GMT)? Pytam o to, ponieważ chcę, aby wszystkie obliczenia były do ​​niego znormalizowane. Ponadto, jak mam zrobić odwrotnie: przekonwertować czas epoki na LocalDate / LocalDateTime (również bez ZoneId lub z GMT)?
programista Androida
2
Nieważne. Znalazłem to:ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0))
programista Androida,
7
Prostsze podejście jest tylko long epoch = time.toEpochSecond(ZoneOffset.UTC)dla przypadków UTC lub gdy znasz już strefę czasową, lub long epoch = time.toEpochSecond(ZoneId.systemDefault());jeśli chcesz jechać tą trasą.
Marcus
To może brzmieć absurdalnie, ale co powiesz na powrót z epoki do LocalDate, LocalTime i LocalDateTime
samuel owino
Nieważne, myślę, że to znalazłem; Instant.ofEpochMilli(responseTime).atZone(ZoneId.systemDefault()).toLocalTime()
samuel owino
27

`` Milis od epoki unixowej '' reprezentuje chwilę, więc powinieneś użyć klasy Instant:

private long toEpochMilli(LocalDateTime localDateTime)
{
  return localDateTime.atZone(ZoneId.systemDefault())
    .toInstant().toEpochMilli();
}
Werner Harnisch
źródło
jest niepoprawne w użyciu, ZoneId.systemDefault()ponieważ epoka unix odnosi się do UTC
ACV,
10

Potrzebna konwersja wymaga przesunięcia z UTC / Greewich lub strefy czasowej.

Jeśli masz przesunięcie, istnieje dedykowana metoda na LocalDateTimeto zadanie:

long epochSec = localDateTime.toEpochSecond(zoneOffset);

Jeśli masz tylko ZoneId, możesz uzyskać ZoneOffsetz ZoneId:

ZoneOffset zoneOffset = ZoneId.of("Europe/Oslo").getRules().getOffset(ldt);

Ale możesz znaleźć konwersję przez ZonedDateTimeprostsze:

long epochSec = ldt.atZone(zoneId).toEpochSecond();
JodaStephen
źródło
4
Jeśli zależy Ci tylko na UTC, jestlong epochSec = localDateTime.toEpochSecond(ZoneOffset.UTC);
ruhong,
2

Spójrz na tę metodę, aby zobaczyć, które pola są obsługiwane. Znajdziesz dla LocalDateTime:

NANO_OF_SECOND 
NANO_OF_DAY 
MICRO_OF_SECOND 
MICRO_OF_DAY 
MILLI_OF_SECOND 
MILLI_OF_DAY 
SECOND_OF_MINUTE 
SECOND_OF_DAY 
MINUTE_OF_HOUR 
MINUTE_OF_DAY 
HOUR_OF_AMPM 
CLOCK_HOUR_OF_AMPM 
HOUR_OF_DAY 
CLOCK_HOUR_OF_DAY 
AMPM_OF_DAY 
DAY_OF_WEEK 
ALIGNED_DAY_OF_WEEK_IN_MONTH 
ALIGNED_DAY_OF_WEEK_IN_YEAR 
DAY_OF_MONTH 
DAY_OF_YEAR 
EPOCH_DAY 
ALIGNED_WEEK_OF_MONTH 
ALIGNED_WEEK_OF_YEAR 
MONTH_OF_YEAR 
PROLEPTIC_MONTH 
YEAR_OF_ERA 
YEAR 
ERA 

Pole INSTANT_SECONDS - oczywiście - nie jest obsługiwane, ponieważ LocalDateTimenie może odwoływać się do żadnego absolutnego (globalnego) znacznika czasu. Ale pomocne jest pole EPOCH_DAY, które zlicza dni, które upłynęły od 01.01.1970. Podobne myśli dotyczą typu LocalDate(z jeszcze mniej obsługiwanymi polami).

Jeśli chcesz uzyskać nieistniejące pole milis-od-unix-epoch, potrzebujesz również strefy czasowej do konwersji z typu lokalnego na globalny. Ta konwersja może być znacznie prostsza, zobacz inne posty SO .

Wracając do pytania i liczb w kodzie:

The result 1605 is correct
  => (2014 - 1970) * 365 + 11 (leap days) + 31 (in january 2014) + 3 (in february 2014)
The result 71461 is also correct => 19 * 3600 + 51 * 60 + 1

16105L * 86400 + 71461 = 1391543461 sekund od 1970-01-01T00: 00: 00 (uwaga, brak strefy czasowej) Następnie możesz odjąć przesunięcie strefy czasowej (uważaj na możliwe pomnożenie przez 1000 w milisekundach).

UPDATE po podanej informacji o strefie czasowej:

local time = 1391543461 secs
offset = 3600 secs (Europe/Oslo, winter time in february)
utc = 1391543461 - 3600 = 1391539861

Jak kod JSR-310 z dwoma równoważnymi podejściami:

long secondsSinceUnixEpoch1 =
  LocalDateTime.of(2014, 2, 4, 19, 51, 1).atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();

long secondsSinceUnixEpoch2 =
  LocalDate
    .of(2014, 2, 4)
    .atTime(19, 51, 1)
    .atZone(ZoneId.of("Europe/Oslo"))
    .toEpochSecond();
Meno Hochschild
źródło
1
Dziękuję za wyjaśnienie. Uzyskaj właściwy wynik, używając LocalDateTime time = LocalDateTime.parse("04.02.2014 19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));i wtedy Long epoch = time.atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();.
1

Konwertuj z czytelnej dla człowieka daty na epokę :

long epoch = new java.text.SimpleDateFormat("MM/dd/yyyyHH:mm:ss").parse("01/01/1970 01:00:00").getTime() / 1000;

Konwertuj z epoki na datę czytelną dla człowieka :

String date = new java.text.SimpleDateFormat("MM/dd/yyyyHH:mm:ss").format(new java.util.Date (epoch*1000));

Dla innego konwertera języków: https://www.epochconverter.com

michmich
źródło
0

Jest to jeden sposób bez używania strefy czasowej:

LocalDateTime now = LocalDateTime.now();
long epoch = (now.getLong(ChronoField.EPOCH_DAY) * 86400000) + now.getLong(ChronoField.MILLI_OF_DAY);
aled evans
źródło