Convert java.util.Date to what “java.time” type?
Yes, you definitely should be using the java.time framework whenever possible.
Avoid old date-time classes
The old date-time classes including java.util.Date
, java.util.Calendar
, and java.text.SimpleDateFormat
and such have proven to be poorly designed, confusing, and troublesome. Avoid them where you can. But when you must interoperate with these old types, you can convert between old and new.
Read on for a basic introduction, somewhat over-simplified, to orient you in moving back-and-forth between the old and new date-time classes.
java.time
The java.time framework is defined by JSR 310, inspired by the highly-successful Joda-Time library, and extended by the ThreeTen-Extra project. The bulk of the functionality was back-ported to Java 6 & 7 in the ThreeTen-Backport project, with a further adaptation for Android in the ThreeTenABP project.
What java.time type matches java.util.Date
? Well, a java.util.Date
object basically represents a moment on the timeline in UTC, a combination of a date and a time-of-day. We can translate that to any of several types in java.time. Each is discussed below. Note that some new methods have been added to the old date-time classes to facilitate conversions.
Instant
The building block in java.time is an Instant
, a moment on the timeline in UTC with a resolution of nanoseconds.
Generally you should do much of your business logic in UTC. In such work, Instant
will be used frequently. Pass around Instant
objects, applying a time zone only for presentation to a user. When you do need to apply an offset or time zone, use the types covered further below.
From java.util.Date
to Instant
Given that both Instant
and java.util.Date
are a moment on the timeline in UTC, we can easily move from a java.util.Date
to an Instant
. The old class has gained a new method, java.util.Date::toInstant
.
Instant instant = myUtilDate.toInstant();
You can go the other direction, from an Instant
to a java.util.Date
. But you may lose information about the fractional second. An Instant
tracks nanoseconds, for up to nine digits after the decimal place such as 2016-01-23T12:34:56.123456789Z
. Both java.util.Date & .Calendar are limited to milliseconds, for up to three digits after the decimal place such as 2016-01-23T12:34:56.123Z
. In this example going from Instant
to Date
means truncation of the 456789
.
java.util.Date myUtilDate = java.util.Date.from(instant);
From java.util.Calendar
to Instant
What about a java.util.Calendar
instead of a java.util.Date
? Internal to the Calendar
object, the date-time is tracked as a count of milliseconds from the epoch reference date-time of the first moment of 1970 in UTC (1970-01-01T00:00:00.0Z
). So this value can be converted easily to an Instant
.
Instant instant = myUtilCalendar.toInstant() ;
From java.util.GregorianCalendar
to ZonedDateTime
Even better, if your java.util.Calendar
object is actually a java.util.GregorianCalendar
you can easily go directly to a ZonedDateTime
. This approach has the benefit of retaining the embedded time zone information.
Downcast from the interface of Calendar
to the concrete class of GregorianCalendar
. Then call the toZonedDateTime
and from
methods to go back and forth.
if (myUtilCalendar instanceof GregorianCalendar) {
GregorianCalendar gregCal = (GregorianCalendar) myUtilCalendar; // Downcasting from the interface to the concrete class.
ZonedDateTime zdt = gregCal.toZonedDateTime(); // Create `ZonedDateTime` with same time zone info found in the `GregorianCalendar`
}
Going the other direction…
java.util.Calendar myUtilCalendar = java.util.GregorianCalendar.from(zdt); // Produces an instant of `GregorianCalendar` which implements `Calendar` interface.
As discussed above, beware that you may be losing information about the fraction of a second. The nanoseconds in the java.time type (ZonedDateTime
) gets truncated to milliseconds in the .Calendar
/.GregorianCalendar
.
OffsetDateTime
From an Instant
we can apply an offset-from-UTC to move into a wall-clock time for some locality. An offset is a number of hours, and possibly minutes and seconds, ahead of UTC (eastward) or behind UTC (westward). The ZoneOffset
class represents this idea. The result is an OffsetDateTime
object.
ZoneOffset offset = ZoneOffset.of("-04:00");
OffsetDateTime odt = OffsetDateTime.ofInstant(instant, zoneOffset);
You can go the other direction, from an OffsetDateTime
to a java.util.Date
. Extract an Instant
and then proceed as we saw in code above. As discussed above, any nanoseconds get truncated to milliseconds (data loss).
java.util.Date myUtilDate = java.util.Date.from(odt.toInstant());
ZonedDateTime
Better yet, apply a full time zone. A time zone is an offset plus rules for handling anomalies such as Daylight Saving Time (DST).
Applying a ZoneId
gets you a ZonedDateTime
object. Use a proper time zone name (continent/region). Never use the 3-4 letter abbreviations commonly seen such as EST
or IST
as they are neither standardized nor unique.
ZoneId zoneId = ZoneId.of("America/Montreal");
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, zoneId);
You can go the other direction, from an ZonedDateTime
to a java.util.Date
. Extract an Instant
and then proceed as we saw in code above. As discussed above, any nanoseconds get truncated to milliseconds (data loss).
java.util.Date myUtilDate = java.util.Date.from( zdt.toInstant() );
And we saw further above that a ZonedDateTime
may be converted to a GregorianCalendar
.
LocalDate
Sometimes you may want a date-only value, without time-of-day and without time zone. For that, use a java.time.LocalDate
object.
See this Question for more discussion, Convert java.util.Date to java.time.LocalDate, especially this Answer written by the main man behind the invention of both Joda-Time and java.time.
The key is to go through a ZonedDateTime
(as generated in code above). We need a time zone to determine a date. The date varies around the world, with a new day dawning earlier in the east. For example, after midnight in Paris is a new day while still “yesterday” in Montréal. So while a LocalDate
does not contain a time zone, a time zone is required to determine a LocalDate
.
LocalDate localDate = zdt.toLocalDate();
Converting in the other direction from LocalDate
to a date-time means inventing a time-of-day. You can choose any time-of-day that makes sense in your business scenario. For most people, the first moment of the day makes sense. You may be tempted to hard code that first moment as the time 00:00:00.0
. In some time zones, that time may not be valid as the first moment because of Daylight Saving Time (DST) or other anomalies. So let java.time determine the correct time with a call to atStartOfDay
.
ZonedDateTime zdt = localDate.atStartOfDay(zoneId);
LocalTime
On rare occasion you may want only a time-of-day without a date and without a time zone. This concept is represented by the LocalTime
class. As discussed above with LocalDate
, we need a time zone to determine a LocalTime
even though the LocalTime
object does not contain (does not ‘remember’) that time zone. So, again, we go through a ZonedDateTime
object obtained from an Instant
as seen above.
LocalTime localTime = zdt.toLocalTime();
LocalDateTime
As with the other two Local…
types, a LocalDateTime
has no time zone nor offset assigned. As such you may rarely use this. It gives you a rough idea of a date-time but is not a point on the timeline. Use this if you mean some general date and some time that might be applied to a time zone.
For example, “Christmas starts this year” would be 2016-12-25T00:00:00.0
. Note the lack of any offset or time zone in that textual representation of a LocalDateTime
. Christmas starts sooner in Delhi India than it does in Paris France, and later still in Montréal Québec Canada. Applying each of those areas’ time zone would yield a different moment on the timeline.
LocalDateTime ldt = zdt.toLocalDateTime();
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
.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
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?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
How to convert java.util.Date to java.time.LocalDate and preserve date/time
You can just convert it to instant, set a time zone to UTC, because java.util.Date is using UTC.
public static LocalDate convert (Date date) {
return date.toInstant()
.atZone(ZoneId.of("UTC"))
.toLocalDate();
}
Convert java.util.Date to java.time.LocalDate
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.
Java8 java.util.Date conversion to java.time.ZonedDateTime
To transform an Instant
to a ZonedDateTime
, ZonedDateTime
offers the method ZonedDateTime.ofInstant(Instant, ZoneId)
. So
So, assuming you want a ZonedDateTime
in the default timezone, your code should be
ZonedDateTime d = ZonedDateTime.ofInstant(calculateFromDate.toInstant(),
ZoneId.systemDefault());
Convert java.util.date into java.time.localdate type?
Try this:
Date inputDate = new Date();
LocalDate date = inputDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
I found this duplicated post after answer:
Convert java.util.Date to java.time.LocalDate
How to convert java.util.Date to Java8 java.time.YearMonth
Short answer:
// From Date to YearMonth
YearMonth yearMonth =
YearMonth.from(date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate());
// From YearMonth to Date
// The same as the OP:s answer
final Date convertedFromYearMonth =
Date.from(yearMonth.atDay(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
Explanation:
The JavaDoc of the YearMonth.from(TemporalAccessor)-method says:
The conversion extracts the YEAR and MONTH_OF_YEAR fields. The extraction is only permitted if the temporal object has an ISO chronology, or can be converted to a LocalDate.
So, you need to either be able to:
- extract the
YEAR
andMONTH_OF_YEAR
fields, or - you should use something that can be converted to a
LocalDate
.
Lets try it!
final Date date = new Date();
final Instant instant = date.toInstant();
instant.get(ChronoField.YEAR); // causes an error
This is not possible, an exception is thrown:
java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: Year
at java.time.Instant.get(Instant.java:571)
...
This means that alternative 1 goes out the window. The reason for is explained in this excellent answer about how to convert Date to 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 is a convenient method toInstant() to provide the conversion.
So, a Date
can be converted to an Instant
but that did not help us, did it?
Alternative 2 however proves to be successful. Convert the Instant
to a LocalDate
and then use the YearMonth.from(TemporalAccessor)
-method.
Date date = new Date();
LocalDate localDate = date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
YearMonth yearMonth = YearMonth.from(localDate);
System.out.println("YearMonth: " + yearMonth);
The output is (since the code was executed in January 2015 ;):
YearMonth: 2015-01
Converting between java.time.LocalDateTime and java.util.Date
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.
How to convert Java.Util.Date to System.DateTime
java.util.Date
has a getTime()
method, which returns the date as a millisecond value. The value is the number of milliseconds since Jan. 1, 1970, midnight GMT.
With that knowledge, you can construct a System.DateTime
, that matches this value like so:
public DateTime FromUnixTime(long unixTimeMillis)
{
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return epoch.AddMilliseconds(unixTimeMillis);
}
(method taken from this answer)
Related Topics
Abstract Class VS Interface in Java
How to Inject a Property Value into a Spring Bean Which Was Configured Using Annotations
Is It a Bad Practice to Catch Throwable
Javafx Controller Class Not Working
How to Convert Long to Byte[] and Back in Java
Java: Ternary with No Return. (For Method Calling)
Java 8 Lambdas, Function.Identity() or T->T
Noclassdeffounderror: Wrong Name
Why One Should Prefer Using CSS Over Xpath in Ie
When Should One Use Final for Method Parameters and Local Variables
How to Read Integer Value from the Standard Input in Java
Handling Exceptions from Java Executorservice Tasks
Main Thread VS. UI Thread in Java
How to Measure Distance and Create a Bounding Box Based on Two Latitude+Longitude Points in Java