¿Cómo extraer epoch de LocalDate y LocalDateTime?

102

¿Cómo extraigo el valor de época Longde instancias de LocalDateTimeo LocalDate? He intentado lo siguiente, pero me da otros resultados:

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

Lo que quiero es simplemente el valor 1391539861de la fecha "04.02.2014 19:51:01"y hora local . Mi zona horaria es Europe/OsloUTC + 1 con horario de verano.

Vadim Kotov
fuente
Explique su número esperado 1396468261. Recibo sin corrección de zona horaria: 1391543461 (consulte la edición en mi respuesta). ¡57 días de diferencia!
Meno Hochschild
@MenoHochschild Actualicé mi pregunta con información de zona horaria y corrigí el valor real de GTM a localtime. ¿Existe una manera más fácil de obtener la época de alguna LocalDateTimeotra que calcularla manualmente?
Volviendo de mi pausa, vea mi actualización.
Meno Hochschild

Respuestas:

147

Las clases LocalDatey LocalDateTimeno contienen información sobre la zona horaria o el desplazamiento de tiempo , y los segundos desde época serían ambiguos sin esta información. Sin embargo, los objetos tienen varios métodos para convertirlos en objetos de fecha / hora con zonas horarias pasando una ZoneIdinstancia.

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
fuente
2
¿Es posible evitar el uso de ZoneId o usarlo con una instancia de ZoneId constante y personalizada (de +0, que significa GMT)? Pregunto esto porque quiero que todos los cálculos estén normalizados. Además, ¿cómo puedo hacer lo contrario: convertir de tiempo de época a LocalDate / LocalDateTime (también sin ZoneId, o con el GMT)?
desarrollador de Android
2
No importa. Encontrado:ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0))
desarrollador de Android
7
Un enfoque más simple es solo long epoch = time.toEpochSecond(ZoneOffset.UTC)para casos UTC, o donde ya conoce la zona horaria, o long epoch = time.toEpochSecond(ZoneId.systemDefault());si desea seguir esa ruta.
Marcus
Esto puede sonar ridículo, pero ¿qué tal si volvemos de época a LocalDate, LocalTime y LocalDateTime?
samuel owino
No importa, creo que lo encontré; Instant.ofEpochMilli(responseTime).atZone(ZoneId.systemDefault()).toLocalTime()
samuel owino
27

'Millis desde unix epoch' representa un instante, por lo que debe usar la clase Instant:

private long toEpochMilli(LocalDateTime localDateTime)
{
  return localDateTime.atZone(ZoneId.systemDefault())
    .toInstant().toEpochMilli();
}
Werner Harnisch
fuente
es incorrecto de usar ZoneId.systemDefault()porque la época de Unix se refiere a UTC
ACV
10

La conversión que necesita requiere el desplazamiento de UTC / Greewich o una zona horaria.

Si usted tiene un offset, hay un método específico de LocalDateTimepara esta tarea:

long epochSec = localDateTime.toEpochSecond(zoneOffset);

Si solo tiene un ZoneId, puede obtenerlo ZoneOffseten ZoneId:

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

Pero puede encontrar una conversión ZonedDateTimemás simple:

long epochSec = ldt.atZone(zoneId).toEpochSecond();
JodaStephen
fuente
4
Si solo te importa UTC, existelong epochSec = localDateTime.toEpochSecond(ZoneOffset.UTC);
ruhong
2

Mire este método para ver qué campos son compatibles. Encontrarás para 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 

El campo INSTANT_SECONDS, por supuesto, no es compatible porque LocalDateTimeno puede hacer referencia a ninguna marca de tiempo absoluta (global). Pero lo que es útil es el campo EPOCH_DAY que cuenta los días transcurridos desde 1970-01-01. Pensamientos similares son válidos para el tipo LocalDate(con campos aún menos admitidos).

Si tiene la intención de obtener el campo milis-since-unix-epoch que no existe, también necesita la zona horaria para convertir de un tipo local a global. Esta conversión se puede hacer mucho más simple, vea otras publicaciones SO .

Volviendo a su pregunta y los números en su código:

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 segundos desde 1970-01-01T00: 00: 00 (atención, sin zona horaria) Luego puede restar el desplazamiento de la zona horaria (tenga cuidado con la posible multiplicación por 1000 si está en milisegundos).

ACTUALIZAR después de la información de zona horaria dada:

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

Como código JSR-310 con dos enfoques equivalentes:

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
fuente
1
Gracias por la explicación. Obtuve el resultado correcto usando LocalDateTime time = LocalDateTime.parse("04.02.2014 19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));y luego Long epoch = time.atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();.
1

Convertir de fecha legible por humanos a época :

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

Convertir de época a fecha legible por humanos :

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

Para otro conversor de idiomas: https://www.epochconverter.com

michmich
fuente
0

Esta es una forma sin usar el tiempo como una zona:

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