How to extract epoch from LocalDate and LocalDateTime?

147,546

Solution 1

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

Solution 2

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

Solution 3

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

Solution 4

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

Solution 5

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);
Share:
147,546
Admin
Author by

Admin

Updated on July 08, 2022

Comments

  • Admin
    Admin almost 2 years

    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.

  • Admin
    Admin about 10 years
    Thanks for the explanation. Got the right result by using LocalDateTime time = LocalDateTime.parse("04.02.2014 19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")); and then Long epoch = time.atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();.
  • android developer
    android developer over 6 years
    Is it possible to avoid using ZoneId, or use with a customized, constant ZoneId instance (of +0 , meaning GMT) ? I ask this because I want all calculations be normalized to it. Also, how do I do the opposite: convert from epoch time to LocalDate/LocalDateTime (also without ZoneId, or with the GMT one) ?
  • android developer
    android developer over 6 years
    Never mind. Found it: ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0))
  • ruhong
    ruhong over 6 years
    If you only care about UTC, there is long epochSec = localDateTime.toEpochSecond(ZoneOffset.UTC);
  • Marcus
    Marcus over 5 years
    A simpler approach is just long epoch = time.toEpochSecond(ZoneOffset.UTC) for UTC cases, or where you already know the timezone, or long epoch = time.toEpochSecond(ZoneId.systemDefault()); if you want to go that route.
  • ACV
    ACV over 4 years
    it is incorrect to use ZoneId.systemDefault() because unix epoch refers to UTC
  • Samuel Owino
    Samuel Owino over 4 years
    This might sound ridiculous but how about converting back from epoch to LocalDate, LocalTime & LocalDateTime
  • Samuel Owino
    Samuel Owino over 4 years
    Never mind I think I found it; Instant.ofEpochMilli(responseTime).atZone(ZoneId.systemDefau‌​lt()).toLocalTime()
  • Dasmowenator
    Dasmowenator about 4 years
    I just want to note that ZonedDateTime also exists and is much more useful in my experience since it can parse the Z (or other time zones) at the end of strings into the correct time zone
  • dstibbe
    dstibbe over 3 years
    Do not use ZoneId.systemDefault ... be explicit about what you want, especially since the timezone is gone in the LocalDateTime.
  • Sourabh
    Sourabh over 3 years
    This doesn't answer the question.
  • Jin Kwon
    Jin Kwon about 2 years
    @ACV Are you still agree what you once thought? Did the API designer failed to define ZonedDateTime#toInstant?
  • ACV
    ACV about 2 years
    @JinKwon I was merely refering to the fact that ZoneId.systemDefault() may not necessarily return the timezon the OP was expecting: My timezone is Europe/Oslo. So they should use ZoneId.of("Europe/Oslo") instead as suggested in other answers. As for ZonedDateTime.toInstant() - its javadoc clearly explains the implementation: This returns an Instant representing the same point on the time-line as this date-time. The calculation combines the local date-time and offset.
  • Ernie Thomason
    Ernie Thomason about 2 years
    ZoneId.systemDefault() seems to return UTC, so systemDefault should be fine