Domanda

How do I extract the epoch value to Long from instances of LocalDateTime or LocalDate? I've tried the following, but it gives me other results:

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

What I want is simply the value 1391539861 for the local datetime "04.02.2014 19:51:01". My timezone is Europe/Oslo UTC+1 with daylight saving time.

È stato utile?

Soluzione

The classes LocalDate and LocalDateTime do not contain information about the timezone or time offset, and seconds since epoch would be ambigious without this information. However, the objects have several methods to convert them into date/time objects with timezones by passing a ZoneId instance.

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();

Altri suggerimenti

'Millis since unix epoch' represents an instant, so you should use the Instant class:

private long toEpochMilli(LocalDateTime localDateTime)
{
  return localDateTime.atZone(ZoneId.systemDefault())
    .toInstant().toEpochMilli();
}

The conversion you need requires the offset from UTC/Greewich, or a time-zone.

If you have an offset, there is a dedicated method on LocalDateTime for this task:

long epochSec = localDateTime.toEpochSecond(zoneOffset);

If you only have a ZoneId then you can obtain the ZoneOffset from the ZoneId:

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

But you may find conversion via ZonedDateTime simpler:

long epochSec = ldt.atZone(zoneId).toEpochSecond();

Look at this method to see which fields are supported. You will find for 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 

The field INSTANT_SECONDS is - of course - not supported because a LocalDateTime cannot refer to any absolute (global) timestamp. But what is helpful is the field EPOCH_DAY which counts the elapsed days since 1970-01-01. Similar thoughts are valid for the type LocalDate (with even less supported fields).

If you intend to get the non-existing millis-since-unix-epoch field you also need the timezone for converting from a local to a global type. This conversion can be done much simpler, see other SO-posts.

Coming back to your question and the numbers in your 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 seconds since 1970-01-01T00:00:00 (attention, no timezone) Then you can subtract the timezone offset (watch out for possible multiplication by 1000 if in milliseconds).

UPDATE after given timezone info:

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

As JSR-310-code with two equivalent approaches:

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();

This is one way without using time a zone:

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

Convert from human readable date to epoch:

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

Convert from epoch to human readable date:

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

For other language converter: https://www.epochconverter.com

Extracting two good answers found in comments on this post,

If you only care about UTC (Coordinated Universal Time), there is

final long epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);

or where you already know the timezone

final long epoch = localDateTime.toEpochSecond(ZoneId.systemDefault());

More information from https://docs.oracle.com/javase/8/docs/api/java/time/chrono/ChronoLocalDateTime.html#toEpochSecond-java.time.ZoneOffset-

toEpochSecond

default long toEpochSecond(ZoneOffset offset)

Converts this date-time to the number of seconds from the epoch of 1970-01-01T00:00:00Z.

This combines this local date-time and the specified offset to calculate the epoch-second value, which is the number of elapsed seconds from 1970-01-01T00:00:00Z. Instants on the time-line after the epoch are positive, earlier are negative.

This default implementation calculates from the epoch-day of the date and the second-of-day of the time.

Parameters:

offset - the offset to use for the conversion, not null

Returns:

the number of seconds from the epoch of 1970-01-01T00:00:00Z

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top