What is the best way to convert a java.util.Date
object to the new JDK 8/JSR-310 java.time.LocalDate
?
Date input = new Date();
LocalDate date = ???
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.
Better way is:
Date date = ...;
Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate()
Advantages of this version:
works regardless the input is an instance of java.util.Date
or it's a subclass of java.sql.Date
(unlike @JodaStephen's way). This is common with JDBC-originated data. java.sql.Date.toInstant()
always throws an exception.
it's the same for JDK8 and JDK7 with JSR-310 backport
I personally use an utility class (but it is not backport-compatible):
/**
* Utilities for conversion between the old and new JDK date types
* (between {@code java.util.Date} and {@code java.time.*}).
*
* <p>
* All methods are null-safe.
*/
public class DateConvertUtils {
/**
* Calls {@link #asLocalDate(Date, ZoneId)} with the system default time zone.
*/
public static LocalDate asLocalDate(java.util.Date date) {
return asLocalDate(date, ZoneId.systemDefault());
}
/**
* Creates {@link LocalDate} from {@code java.util.Date} or it's subclasses. Null-safe.
*/
public static LocalDate asLocalDate(java.util.Date date, ZoneId zone) {
if (date == null)
return null;
if (date instanceof java.sql.Date)
return ((java.sql.Date) date).toLocalDate();
else
return Instant.ofEpochMilli(date.getTime()).atZone(zone).toLocalDate();
}
/**
* Calls {@link #asLocalDateTime(Date, ZoneId)} with the system default time zone.
*/
public static LocalDateTime asLocalDateTime(java.util.Date date) {
return asLocalDateTime(date, ZoneId.systemDefault());
}
/**
* Creates {@link LocalDateTime} from {@code java.util.Date} or it's subclasses. Null-safe.
*/
public static LocalDateTime asLocalDateTime(java.util.Date date, ZoneId zone) {
if (date == null)
return null;
if (date instanceof java.sql.Timestamp)
return ((java.sql.Timestamp) date).toLocalDateTime();
else
return Instant.ofEpochMilli(date.getTime()).atZone(zone).toLocalDateTime();
}
/**
* Calls {@link #asUtilDate(Object, ZoneId)} with the system default time zone.
*/
public static java.util.Date asUtilDate(Object date) {
return asUtilDate(date, ZoneId.systemDefault());
}
/**
* Creates a {@link java.util.Date} from various date objects. Is null-safe. Currently supports:<ul>
* <li>{@link java.util.Date}
* <li>{@link java.sql.Date}
* <li>{@link java.sql.Timestamp}
* <li>{@link java.time.LocalDate}
* <li>{@link java.time.LocalDateTime}
* <li>{@link java.time.ZonedDateTime}
* <li>{@link java.time.Instant}
* </ul>
*
* @param zone Time zone, used only if the input object is LocalDate or LocalDateTime.
*
* @return {@link java.util.Date} (exactly this class, not a subclass, such as java.sql.Date)
*/
public static java.util.Date asUtilDate(Object date, ZoneId zone) {
if (date == null)
return null;
if (date instanceof java.sql.Date || date instanceof java.sql.Timestamp)
return new java.util.Date(((java.util.Date) date).getTime());
if (date instanceof java.util.Date)
return (java.util.Date) date;
if (date instanceof LocalDate)
return java.util.Date.from(((LocalDate) date).atStartOfDay(zone).toInstant());
if (date instanceof LocalDateTime)
return java.util.Date.from(((LocalDateTime) date).atZone(zone).toInstant());
if (date instanceof ZonedDateTime)
return java.util.Date.from(((ZonedDateTime) date).toInstant());
if (date instanceof Instant)
return java.util.Date.from((Instant) date);
throw new UnsupportedOperationException("Don't know hot to convert " + date.getClass().getName() + " to java.util.Date");
}
/**
* Creates an {@link Instant} from {@code java.util.Date} or it's subclasses. Null-safe.
*/
public static Instant asInstant(Date date) {
if (date == null)
return null;
else
return Instant.ofEpochMilli(date.getTime());
}
/**
* Calls {@link #asZonedDateTime(Date, ZoneId)} with the system default time zone.
*/
public static ZonedDateTime asZonedDateTime(Date date) {
return asZonedDateTime(date, ZoneId.systemDefault());
}
/**
* Creates {@link ZonedDateTime} from {@code java.util.Date} or it's subclasses. Null-safe.
*/
public static ZonedDateTime asZonedDateTime(Date date, ZoneId zone) {
if (date == null)
return null;
else
return asInstant(date).atZone(zone);
}
}
The asLocalDate()
method here is null-safe, uses toLocalDate()
, if input is java.sql.Date
(it may be overriden by the JDBC driver to avoid timezone problems or unnecessary calculations), otherwise uses the abovementioned method.
If you're using Java 8, @JodaStephen's answer is obviously the best. However, if you're working with the JSR-310 backport, you unfortunately have to do something like this:
Date input = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(input);
LocalDate date = LocalDate.of(cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH) + 1,
cal.get(Calendar.DAY_OF_MONTH));
Date input = new Date();
LocalDateTime conv=LocalDateTime.ofInstant(input.toInstant(), ZoneId.systemDefault());
LocalDate convDate=conv.toLocalDate();
The Date
instance does contain time too along with the date while LocalDate
doesn't. So you can firstly convert it into LocalDateTime
using its method ofInstant()
then if you want it without time then convert the instance into LocalDate
.
public static LocalDate Date2LocalDate(Date date) {
return LocalDate.parse(date.toString(), DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy"))
this format is from Date#tostring
public String toString() {
// "EEE MMM dd HH:mm:ss zzz yyyy";
BaseCalendar.Date date = normalize();
StringBuilder sb = new StringBuilder(28);
int index = date.getDayOfWeek();
if (index == BaseCalendar.SUNDAY) {
index = 8;
}
convertToAbbr(sb, wtb[index]).append(' '); // EEE
convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
TimeZone zi = date.getZone();
if (zi != null) {
sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
} else {
sb.append("GMT");
}
sb.append(' ').append(date.getYear()); // yyyy
return sb.toString();
}
I have had problems with @JodaStephen's implementation on JBoss EAP 6. So, I rewrote the conversion following Oracle's Java Tutorial in http://docs.oracle.com/javase/tutorial/datetime/iso/legacy.html.
Date input = new Date();
GregorianCalendar gregorianCalendar = (GregorianCalendar) Calendar.getInstance();
gregorianCalendar.setTime(input);
ZonedDateTime zonedDateTime = gregorianCalendar.toZonedDateTime();
zonedDateTime.toLocalDate();
Date input = new Date(); // Imagine your Date here
LocalDate date = DateTimeUtils.toInstant(input)
.atZone(ZoneId.systemDefault())
.toLocalDate();
If you are using the backport of JSR 310, either you haven’t got a Date.toInstant()
method or it won’t give you the org.threeten.bp.Instant
that you need for you further conversion. Instead you need to use the DateTimeUtils
class that comes as part of the backport. The remainder of the conversion is the same, so so is the explanation.
I solved this question with solution below
import org.joda.time.LocalDate;
Date myDate = new Date();
LocalDate localDate = LocalDate.fromDateFields(myDate);
System.out.println("My date using Date" Nov 18 11:23:33 BRST 2016);
System.out.println("My date using joda.time LocalTime" 2016-11-18);
In this case localDate print your date in this format "yyyy-MM-dd"