Your Java application might be using a downstream service that stores the date according to the number of milliseconds since the current epoch began.

But you might need to work with that "date" by using the Java 8 date and time library. So, you need to translate that Long number into a LocalDate or LocalDateTime object.

It's a little more complicated to do than it should be. But once you understand the pattern, you can do it easily time and time again.

Get Thee a Time Zone

The first thing you need to do is get the time zone that the application is using.

Fortunately, that's pretty easy here. Because the epoch time passage is measured in the UTC time zone.

So all you need to do is grab that UTC time zone with the ZoneId object.

The ZoneId Object

Fortunately, Java 8 makes it pretty easy to convert a given time zone to a ZoneId object. You can do so with the of() method.

Yep. It's called of(). And it's a static method.

You can use it like this:

ZoneId.of("UTC")

That will get you the UTC time zone.

By the way, if you're wondering about all the possible values you can put in that of() method, you can just invoke getAvailableZoneIds() (also a static method) on the ZoneId class.

Also, if you need to work with a time zone other than UTC, check out my guide on converting from one time zone to another using the Java 8 date and time library.

In an Instant

Now that you've got the milliseconds since the epoch began as well as the time zone, you can start making the magic thing happen.

First, start with the Instant class. It represents an instant in time.

And, like other classes in the Java 8 date and time library, it's got a static method that works really well for this situation: ofEpochMilli().

That's going to create an instance of Instant (weird, right?) that represents a moment in time specified by the Long value you pass in.

So if the service you're working with gave you 1618790400000 as the number of milliseconds since the epoch began, you can generate an Instant object like this:

Long dateValue = 1618790400000l;

Instant instant = Instant.ofEpochMilli(dateValue);

But that still ain't gonna get you what you want. You need to take things a little further.

A Little Further

At this point, you've got an Instant object, but you don't have it specific to a time zone. So try this:

Long dateValue = 1618790400000l;

ZonedDateTime zdt = Instant.ofEpochMilli(dateValue).atZone(ZoneId.of("UTC"));

Getting warmer. But all that does is give you a ZonedDateTime object. You want a LocalDate or LocalDateTime object.

So try this:

Long dateValue = 1618790400000l;
            
LocalDate date = Instant.ofEpochMilli(dateValue)
                        .atZone(ZoneId.of("UTC"))
                        .toLocalDate();

System.err.println(date);

That toLocalDate() method gives you exactly what you're looking for.

Now you have a representation of the date independent of the time zone.

That code, by the way, will print out:

2021-04-19

That's because the Long number you see in the first line of the code represents April 19, 2021 at the start of the day in the UTC time zone.

So it worked.

And if you'd like to go with LocalDateTime:

Long dateValue = 1618790400000l;
            
LocalDateTime dateTime = Instant.ofEpochMilli(dateValue)
                        .atZone(ZoneId.of("UTC"))
                        .toLocalDateTime();

System.err.println(dateTime);

That will print out:

2021-04-19T00:00

Houston, we have no problems!

Wrapping It Up

Now you know how to convert epoch milliseconds in to a Java LocalDate or LocalDateTime object

Feel free to use what you've learned here in your own Java applications.

Have fun!

Photo by Olya Kobruseva from Pexels