Short answer
Date input = new Date();
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Explanation
Despite its name, Java.util.Date
it represents an instant on the timeline, not a “date”. The actual data stored in the object is a count long
milliseconds since 1970-01-01T00: 00Z (midnight to early 1970 GMT / UTC).
The class equivalent to Java.util.Date
in JSR-310 is Instant
so there is a convenient method toInstant()
to provide the conversion:
Date input = new Date();
Instant instant = input.toInstant();
An instance of Java.util.Date
it has no concept of time zone. This might sound weird if you call toString()
on a Java.util.Date
Why toString
is relative to a time zone. However, that method actually uses Java’s default time zone on the fly to provide the string. The time zone is not part of the current state of Java.util.Date
.
Also an Instant
it does not contain any time zone information. Therefore, to convert from Instant
on a local date, a time zone must be specified. This could be the default zone – ZoneId.systemDefault()
– or it could be a time zone controlled by the application, for example a time zone from user preferences. Use the method atZone()
to apply the time zone:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
TO ZonedDateTime
contains the status consisting of the local date and time, time zone and the offset from GMT / UTC. As such the date – LocalDate
– can be easily extracted using toLocalDate()
:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
LocalDate date = zdt.toLocalDate();
Java 9 answer
In Java SE 9, a new method which simplifies this task slightly:
Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());
This new alternative is more direct, creates less waste, and therefore should work better.