140

Is there a simple way to convert a LocalDate (introduced with Java 8) to java.util.Date object?

By 'simple', I mean simpler than this:

Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());

which seems a bit awkward to me.

Since we are interested only in the date portion and there is no timezone information in neither of the objects, why introduce time zones explicitly? The midnight time and the system default timezone should be taken implicitly for the conversion.

Nathan Hughes
  • 85,411
  • 19
  • 161
  • 250
George
  • 6,216
  • 7
  • 28
  • 40
  • 4
    If youre using Java 8 you should probably avoid `java.util.Date` altogether – Reimeus Oct 11 '15 at 15:54
  • 4
    "Since we are interested only in the date portion" problem is that `java.util.Date` by default is expected not only to represent informations about day (year/month/day), but also about time of day so we need to somehow provide this informations (here helps `atStartOfDay`). – Pshemo Oct 11 '15 at 15:54
  • 2
    A `LocalDate` is **not** an instant in time, it is a _date_, such as "30 Jan 2014". It is not tied to any particular instant _until you give it a time zone_. I'm not entirely sure you understand what you are asking... – Boris the Spider Oct 11 '15 at 15:55
  • 6
    A Date represents a precise instant. A LocalDate doesn't. It's just a set of fields. You thus need to specify a timezone to transform this set of fields to an instant: 2015-10-11T00:00 is not the same instant in Paris and in New York. – JB Nizet Oct 11 '15 at 15:56
  • 1
    @Reimeus Actually that is the case. As I am using the new java time api, there are APIs (e.g. JDBC) which takes dates and times from java.util or java.sql packages. Hence the required conversion. – George Oct 11 '15 at 19:20
  • 2
    @JBNizet I'm not certain that that's the easiest way to understand it. Both `Date` and `Instant` are internally reckoned in UTC and (thankfully) have no notion of local time zone. `LocalDate` and `LocalDateTime` are intended to represent their respective temporal values in arbitrary local time zones which most of the time are not UTC. Hence there is no simple, historically consistent way to directly convert from one form to the other without knowing more information. – scottb Oct 11 '15 at 20:05
  • 7
    @Reimeus: if he's using an older API, then he may have no choice but to use `Date`. The `@Basic` annotation of JPA 2.1, for example, directly recognizes `Date` and `Calendar` but will only work with `Instant` as a serializable type. I would say he's doing the right thing by using the new Date-Time API in his new code and using `Date` to interoperate. – scottb Oct 11 '15 at 20:10
  • 2
    *"Since we are interested only in the date portion and there is no timezone information in neither of the objects why introduce time zones here?"* ... you may think there is no time zone here, but there always is whenever (whenever) there is a notion of time. The timestamps "07-Sep-2015T17:30" and "07-Sep-2015T22:30" in U.S. Central Daylight Time have the same dates locally but different dates in UTC (and, therefore, different dates as Instants). – scottb Oct 11 '15 at 20:20
  • 5
    @George: the general contract for `Date` and `Instant` both include the notion of time. Interconverting between `LocalDate` and `Date` therefore means that you are necessarily dealing with a notion of time, even if you don't intend to use time information. You can't convert from "07-Sept-2015 in some local time zone" (`LocalDate`) to "milliseconds since midnight 01-Jan-1970 UTC" (`Date`) without knowing what "some local time zone" is. – scottb Oct 11 '15 at 22:04

7 Answers7

143

tl;dr

Is there a simple way to convert a LocalDate (introduced with Java 8) to java.util.Date object? By 'simple', I mean simpler than this

Nope. You did it properly, and as concisely as possible.

java.util.Date.from(                     // Convert from modern java.time class to troublesome old legacy class.  DO NOT DO THIS unless you must, to inter operate with old code not yet updated for java.time.
    myLocalDate                          // `LocalDate` class represents a date-only, without time-of-day and without time zone nor offset-from-UTC. 
    .atStartOfDay(                       // Let java.time determine the first moment of the day on that date in that zone. Never assume the day starts at 00:00:00.
        ZoneId.of( "America/Montreal" )  // Specify time zone using proper name in `continent/region` format, never 3-4 letter pseudo-zones such as “PST”, “CST”, “IST”. 
    )                                    // Produce a `ZonedDateTime` object. 
    .toInstant()                         // Extract an `Instant` object, a moment always in UTC.
)

Read below for issues, and then think about it. How could it be simpler? If you ask me what time does a date start, how else could I respond but ask you “Where?”?. A new day dawns earlier in Paris FR than in Montréal CA, and still earlier in Kolkata IN, and even earlier in Auckland NZ, all different moments.

So in converting a date-only (LocalDate) to a date-time we must apply a time zone (ZoneId) to get a zoned value (ZonedDateTime), and then move into UTC (Instant) to match the definition of a java.util.Date.

Details

Firstly, avoid the old legacy date-time classes such as java.util.Date whenever possible. They are poorly designed, confusing, and troublesome. They were supplanted by the java.time classes for a reason, actually, for many reasons.

But if you must, you can convert to/from java.time types to the old. Look for new conversion methods added to the old classes.

Table of all date-time types in Java, both modern and legacy

java.util.Datejava.time.LocalDate

Keep in mind that a java.util.Date is a misnomer as it represents a date plus a time-of-day, in UTC. In contrast, the LocalDate class represents a date-only value without time-of-day and without time zone.

Going from java.util.Date to java.time means converting to the equivalent class of java.time.Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Instant instant = myUtilDate.toInstant();

The LocalDate class represents a date-only value without time-of-day and without time zone.

A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.

So we need to move that Instant into a time zone. We apply ZoneId to get a ZonedDateTime.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

From there, ask for a date-only, a LocalDate.

LocalDate ld = zdt.toLocalDate();

java.time.LocalDatejava.util.Date

To move the other direction, from a java.time.LocalDate to a java.util.Date means we are going from a date-only to a date-time. So we must specify a time-of-day. You probably want to go for the first moment of the day. Do not assume that is 00:00:00. Anomalies such as Daylight Saving Time (DST) means the first moment may be another time such as 01:00:00. Let java.time determine that value by calling atStartOfDay on the LocalDate.

ZonedDateTime zdt = myLocalDate.atStartOfDay( z );

Now extract an Instant.

Instant instant = zdt.toInstant();

Convert that Instant to java.util.Date by calling from( Instant ).

java.util.Date d = java.util.Date.from( instant );

More info


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. Hibernate 5 & JPA 2.2 support java.time.

Where to obtain the java.time classes?

Table of which java.time library to use with which version of Java or Android

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.

Basil Bourque
  • 218,480
  • 72
  • 657
  • 915
140

Disclaimer: While the answer below works, it is not recommended to be used in production code. The approach in the Basil's answer should be followed in this case.

Actually there is. There is a static method valueOf in the java.sql.Date object which does exactly that. So we have

java.util.Date date = java.sql.Date.valueOf(localDate);

and that's it. No explicit setting of time zones because the local time zone is taken implicitly.

From docs:

The provided LocalDate is interpreted as the local date in the local time zone.

The java.sql.Date subclasses java.util.Date so the result is a java.util.Date also.

And for the reverse operation there is a toLocalDate method in the java.sql.Date class. So we have:

LocalDate ld = new java.sql.Date(date.getTime()).toLocalDate();

George
  • 6,216
  • 7
  • 28
  • 40
  • 4
    The original question Date is also in system timezone. Using java.sql.Date for a actual date is not that far fetched, IMHO. – eckes Oct 11 '15 at 17:04
  • 17
    This answer can NOT be recommended because a) it lacks support for different timezones and b) mix up two different types where the inheritance relationship only denotes an implementation-driven dependency. The type `java.sql.Date` should only be applied in context of JDBC. Best answer see that from @Basil Bourque – Meno Hochschild Oct 21 '16 at 10:19
  • 5
    As Hochschild said, the class doc tells us to ignore the inheritance subclass relationship between java.util.Date & java.sql.Date, tells us to *not* do what this Answer does. Furthermore that `valueOf` method does *not* skirt the issue of time zone, it merely *hides* the issue while silently applying the JVM’s current default zone in setting the time-of-day to midnight. So the statement “No time zones, no complications” is **incorrect**: There *are* time zones involved, and there *are* complications, you've just chosen to ignore them. The java.time classes were invented for a reason; use them. – Basil Bourque Nov 18 '16 at 16:20
  • 79
    As the author of the `java.time.*` libraries I am saddened that over 40 people have seen fit to upvote this. The correct answer is [here](http://stackoverflow.com/a/21242111/38896) and Basil's below. Using `java.sql.Date` is a horrible hack as expressed in other comments and this approach hides the time-zone conversion, which is a Bad Thing. It has also been known for years that `java.sql.Date` should never have extended `java.util.Date`. Finally, when using modules in Java 9, the `java.sql` classes will be a separate dependency, so using this hack will have consequences. – JodaStephen Mar 16 '17 at 09:27
  • @JodaStephen I think the problem lies with old JDBC APIs which pass back `java.sql.Dates` which can then easily be cast down to `java.util.Date` by unsuspecting intermediate classes and then when you call `java.util.Date::toInstant()`, you get an `UnsupportedOperationException` from `java.sql.Date` :( – Adam Oct 17 '17 at 15:07
  • 5
    Its a hack at best. Please ignore this answer. And instead see @BasilBourque's [answer](https://stackoverflow.com/a/40143687/468763) – Prakash K Nov 30 '17 at 12:03
19

Date -> LocalDate:

LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

LocalDate -> Date:

Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
Hai Nguyen
  • 761
  • 10
  • 9
  • 3
    if your `java.util.Date` is actually a `java.sql.Date`, then this will give you an `UnsupportedOperationException` – Adam Oct 17 '17 at 14:55
3

Converting LocalDateTime to java.util.Date

    LocalDateTime localDateTime = LocalDateTime.now();

    ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneOffset.systemDefault());

    Instant instant = zonedDateTime.toInstant();

    Date date = Date.from(instant);

System.out.println("Result Date is : "+date);
Simhadri
  • 41
  • 4
3

Date to LocalDate

Date date = new Date();
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

LocalDate to Date

LocalDate localDate = LocalDate.now();
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
Jayendran
  • 6,972
  • 4
  • 39
  • 80
fjkjava
  • 977
  • 15
  • 22
-2

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"

estevamdf
  • 25
  • 4
  • Typo? Did you mean to pass `date` rather than `data`? – Basil Bourque Nov 18 '16 at 16:29
  • 1
    Please cite the documentation for that method. I do not see that method on the [class doc for `java.time.LocalDate`](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html). – Basil Bourque Nov 18 '16 at 16:32
  • My bad. My bad. I forgot copy the variable. – estevamdf Nov 18 '16 at 19:03
  • 1
    You can edit your Answer to correct the typo. And clarify the source of that method you used. Seems to be from Joda-Time, but this Question is about `java.time.LocalDate`. The Joda-Time project is now in maintenance mode, with the team advising migration to java.time. – Basil Bourque Nov 19 '16 at 01:17
  • Thanks @BasilBourque for your observation. In this case i used the class LocalDate of package: org.joda.time Fixing the answer I solved this issue with the 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); ` – estevamdf Nov 21 '16 at 11:44
  • I suggest this other answer available in this stack: http://stackoverflow.com/questions/21242110/convert-java-util-date-to-java-time-localdate In this case was used the class of org.time.LocalDate. – estevamdf Nov 21 '16 at 12:05
  • The Joda-Time project is now in maintenance mode. Its team advises migration to the java.time classes built into Java 8 and later. For Java 6 & 7 use the ThreeTen-Backport project. – Basil Bourque Jun 01 '17 at 16:41
-4

You can convert the java.util.Date object into a String object, which will format the date as yyyy-mm-dd.

LocalDate has a parse method that will convert it to a LocalDate object. The string must represent a valid date and is parsed using DateTimeFormatter.ISO_LOCAL_DATE.

Date to LocalDate

LocalDate.parse(Date.toString())
  • 2
    You have obivously not tested your code suggestion, otherwise you would have seen an exception because `java.time.LocalDate` expects an ISO-formatted string, not the std-output of `java.util.Date`. Deserves a downvote, but today I have a good day ;-) The best answer here is given by Basil Bourque. – Meno Hochschild Oct 21 '16 at 10:15