Short answer:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
Explanation:
(based on this question about LocalDate
)
Despite its name, java.util.Date
represents an instant on the time-line, not a "date". The actual data stored within the object is a long
count of milliseconds since 1970-01-01T00:00Z (midnight at the start of 1970 GMT/UTC).
The equivalent class to java.util.Date
in JSR-310 is Instant
, thus there are convenient methods to provide the conversion to and fro:
Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);
A java.util.Date
instance has no concept of time-zone. This might seem strange if you call toString()
on a java.util.Date
, because the 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 actual state of java.util.Date
.
An Instant
also does not contain any information about the time-zone. Thus, to convert from an Instant
to a local date-time it is necessary to specify a time-zone. This might be the default zone - ZoneId.systemDefault()
- or it might be a time-zone that your application controls, such as a time-zone from user preferences. LocalDateTime
has a convenient factory method that takes both the instant and time-zone:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
In reverse, the LocalDateTime
the time-zone is specified by calling the atZone(ZoneId)
method. The ZonedDateTime
can then be converted directly to an Instant
:
LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());
Note that the conversion from LocalDateTime
to ZonedDateTime
has the potential to introduce unexpected behaviour. This is because not every local date-time exists due to Daylight Saving Time. In autumn/fall, there is an overlap in the local time-line where the same local date-time occurs twice. In spring, there is a gap, where an hour disappears. See the Javadoc of atZone(ZoneId)
for more the definition of what the conversion will do.
Summary, if you round-trip a java.util.Date
to a LocalDateTime
and back to a java.util.Date
you may end up with a different instant due to Daylight Saving Time.
Additional info: There is another difference that will affect very old dates. java.util.Date
uses a calendar that changes at October 15, 1582, with dates before that using the Julian calendar instead of the Gregorian one. By contrast, java.time.*
uses the ISO calendar system (equivalent to the Gregorian) for all time. In most use cases, the ISO calendar system is what you want, but you may see odd effects when comparing dates before year 1582.
Short answer
Date input = new Date();
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Explanation
Despite its name, java.util.Date
represents an instant on the time-line, not a "date". The actual data stored within the object is a long
count of milliseconds since 1970-01-01T00:00Z (midnight at the start of 1970 GMT/UTC).
The equivalent class to java.util.Date
in JSR-310 is Instant
, thus there is a convenient method toInstant()
to provide the conversion:
Date input = new Date();
Instant instant = input.toInstant();
A java.util.Date
instance has no concept of time-zone. This might seem strange if you call toString()
on a java.util.Date
, because the 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 actual state of java.util.Date
.
An Instant
also does not contain any information about the time-zone. Thus, to convert from an Instant
to a local date it is necessary to specify a time-zone. This might be the default zone - ZoneId.systemDefault()
- or it might be a time-zone that your application controls, such as a time-zone from user preferences. Use the atZone()
method to apply the time-zone:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
A ZonedDateTime
contains state 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 has been added that slightly simplifies this task:
Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());
This new alternative is more direct, creating less garbage, and thus should perform better.
Best Answer
LocalDateTime
means no zoneYou seem to misunderstand the purpose of
LocalDateTime
.This class has no time zone and no offset-from-UTC. It is not a point on the timeline. Rather it represents a vague idea about possible moments. The name “Local…” may be counter-intuitive as it does not represent any particular locality, but rather any locality.
For example, Christmas this year is midnight at start of December 25, 2016, or
2016-12-25T00:00
. This has no meaning until you apply a time zone to get Christmas in Auckland NZ or Kolkata IN or Paris FR or Montréal CA, each being a different point on the timeline, getting later and later as you go westward.Never use
LocalDateTime
because you think it will save you the hassle of zones and offsets. Just the opposite, you’ll be digging yourself into a hole with ambiguous date-time values.Focus on UTC
Most of your business logic, logging, data storage, and data exchange should all be in UTC. Think of UTC as the one true time; all the other zones and offsets are masquerading as dressed-up UTC values.
In java.time, that means the
Instant
class is your go-to class, the basic building-blocks of date-time objects. TheInstant
class represents a moment on the timeline in UTC with a resolution of nanoseconds.ZonedDateTime
Adjust into time zones only where required to access the wall-clock time of some region. Apply a
ZoneId
to get aZonedDateTime
object.All three of these objects,
now
,zdtNewYork
, andzdtRecife
, are all the very some moment, the same simultaneous point on the timeline. All three share the same count-from-epoch. The only difference is the lens through which we see their wall-clock time.Avoid legacy date-time classes
Avoid using the troublesome old date-time classes bundled with the earliest versions of Java. So, avoid
java.util.Date
andjava.util.Calendar
. They really are that bad. Stick with java.time classes.If you must interact with old code not yet updated for java.time types, you can convert to/from java.time types. Look for new methods added to the old classes. The
java.util.Date.from
method takes anInstant
. We can extract anInstant
from aZoneDateTime
(or fromOffsetDateTime
).And going the other direction.
For more info on converting, see my Answer to the Question, Convert java.util.Date to what “java.time” type?
Avoid count-from-epoch
Avoid using the count-from-epoch numbers such as milliseconds-since-start-of-1970-in-UTC. There are various granularities used for the count (milliseconds, microseconds, nanoseconds, whole seconds, and more). There are at least a couple dozen epochs in use by various computer systems besides 1970. The numbers have no meaning when read by humans, so bugs may go undetected.
You might find them useful when practicing. Call
getEpochSecond
andgetNano
onInstant
, or for a truncated value calltoEpochMilli
.About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as
java.util.Date
,Calendar
, &SimpleDateFormat
.The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for
java.sql.*
classes.Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as
Interval
,YearWeek
,YearQuarter
, and more.