Comment extraire l'époque de LocalDate et LocalDateTime?

102

Comment extraire la valeur d'époque vers Longdes instances de LocalDateTimeou LocalDate? J'ai essayé ce qui suit, mais cela me donne d'autres résultats:

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

Ce que je veux, c'est simplement la valeur 1391539861de la date / heure locale "04.02.2014 19:51:01". Mon fuseau horaire est Europe/OsloUTC + 1 avec l'heure d'été.

Vadim Kotov
la source
Veuillez expliquer votre nombre attendu 1396468261. Je reçois sans correction de fuseau horaire: 1391543461 (voir modifier dans ma réponse). 57 jours de différence!
Meno Hochschild
@MenoHochschild J'ai mis à jour ma question avec les informations de fuseau horaire et corrigé la valeur réelle de GTM à l'heure locale. Existe-t-il un moyen plus simple d'obtenir l'époque de certains LocalDateTimeautres que de le calculer manuellement?
En revenant de ma pause, consultez ma mise à jour.
Meno Hochschild

Réponses:

147

Les classes LocalDateet LocalDateTimene contiennent pas d'informations sur le fuseau horaire ou le décalage horaire , et les secondes depuis l'époque seraient ambiguës sans ces informations. Cependant, les objets ont plusieurs méthodes pour les convertir en objets date / heure avec des fuseaux horaires en passant une ZoneIdinstance.

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
la source
2
Est-il possible d'éviter d'utiliser ZoneId ou de l'utiliser avec une instance de ZoneId personnalisée et constante (de +0, signifiant GMT)? Je demande cela parce que je veux que tous les calculs y soient normalisés. Aussi, comment faire le contraire: convertir l'heure de l'époque en LocalDate / LocalDateTime (également sans ZoneId, ou avec celui GMT)?
développeur android
2
Ça ne fait rien. Trouvé:ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0))
développeur Android
7
Une approche plus simple est juste long epoch = time.toEpochSecond(ZoneOffset.UTC)pour les cas UTC, ou lorsque vous connaissez déjà le fuseau horaire, ou long epoch = time.toEpochSecond(ZoneId.systemDefault());si vous souhaitez emprunter cette route.
Marcus
Cela peut sembler ridicule, mais que diriez-vous de revenir de l'époque à LocalDate, LocalTime et LocalDateTime
Samuel Owino
Peu importe, je pense que je l'ai trouvé; Instant.ofEpochMilli(responseTime).atZone(ZoneId.systemDefault()).toLocalTime()
samuel owino le
27

'Millis since unix epoch' représente un instant, vous devez donc utiliser la classe Instant:

private long toEpochMilli(LocalDateTime localDateTime)
{
  return localDateTime.atZone(ZoneId.systemDefault())
    .toInstant().toEpochMilli();
}
Werner Harnisch
la source
il est incorrect à utiliser ZoneId.systemDefault()car l'époque Unix fait référence à UTC
ACV
10

La conversion dont vous avez besoin nécessite le décalage par rapport à UTC / Greewich, ou un fuseau horaire.

Si vous avez un décalage, il y a un méthode dédiée à LocalDateTimecette tâche:

long epochSec = localDateTime.toEpochSecond(zoneOffset);

Si vous n'avez qu'un ZoneId vous pouvez l'obtenir ZoneOffsetauprès du ZoneId:

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

Mais vous pouvez trouver une conversion ZonedDateTimeplus simple:

long epochSec = ldt.atZone(zoneId).toEpochSecond();
JodaStephen
la source
4
Si vous ne vous souciez que de l'UTC, il y along epochSec = localDateTime.toEpochSecond(ZoneOffset.UTC);
ruhong
2

Regardez cette méthode pour voir quels champs sont pris en charge. Vous trouverez pour 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 

Le champ INSTANT_SECONDS n'est bien entendu pas pris en charge car a LocalDateTimene peut faire référence à aucun horodatage absolu (global). Mais ce qui est utile, c'est le champ EPOCH_DAY qui compte les jours écoulés depuis le 1970-01-01. Des pensées similaires sont valables pour le typeLocalDate (avec encore moins de champs pris en charge).

Si vous avez l'intention d'obtenir le champ millis-since-unix-epoch non existant, vous avez également besoin du fuseau horaire pour passer d'un type local à un type global. Cette conversion peut être effectuée beaucoup plus simplement, voir d'autres articles SO .

Pour revenir à votre question et aux chiffres de votre code:

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 secondes depuis le 1970-01-01T00: 00: 00 (attention, pas de fuseau horaire) Ensuite, vous pouvez soustraire le décalage du fuseau horaire (attention à la multiplication possible par 1000 si en millisecondes).

MISE À JOUR après avoir donné les informations de fuseau horaire:

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

En tant que code JSR-310 avec deux approches équivalentes:

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
la source
1
Merci pour l'explication. Vous avez obtenu le bon résultat en utilisant LocalDateTime time = LocalDateTime.parse("04.02.2014 19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));et ensuite Long epoch = time.atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();.
1

Conversion de la date lisible par l'homme à l'époque :

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

Conversion de l' époque en date lisible par l'homme :

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

Pour un autre convertisseur de langue: https://www.epochconverter.com

Michmich
la source
0

C'est une façon sans utiliser le temps un fuseau:

LocalDateTime now = LocalDateTime.now();
long epoch = (now.getLong(ChronoField.EPOCH_DAY) * 86400000) + now.getLong(ChronoField.MILLI_OF_DAY);
aled evans
la source