Should I Use Java.Util.Date or Switch to Java.Time.Localdate

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.

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();
}

LocalDate to java.util.Date and vice versa simplest conversion?

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

  • Oracle Tutorial
  • Similar Question, Convert java.util.Date to what “java.time” type?


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?

  • 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 brought 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 (26+) bundle implementations of the java.time classes.
    • For earlier Android (<26), a process known as API desugaring brings a subset of the java.time functionality not originally built into Android.
      • If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….

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.

java.time.LocalDate to java.util.Date

LocalDate ld = ...;
Instant instant = ld.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
Date res = Date.from(instant);

Check out this blog post, Converting between Date and java8 java.time.LocalDateTime, LocalDate and LocalTime by joachim.

Choosing between java.util.Date or java.sql.Date

tl;dr

Should I use java.util.Date or java.sql.Date?

Neither.

Both are obsolete as of JDBC 4.2 and later. Use java.time classes instead.

  • date-only value
    For a database type akin to SQL-standard DATE, use java.time.LocalDate.

    • LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
    • myPreparedStatement.setObject( ld , … ) ;
  • date with time-of-day in UTC value
    For a database type akin to SQL-standard TIMESTAMP WITH TIME ZONE, use java.time.Instant.

    • Instant instant = myResultSet.getObject( … , Instant.class ) ;
    • myPreparedStatement.setObject( instant , … ) ;

Details

The question and other answers seem to be over-thinking the issue. A java.sql.Date is merely a java.util.Date with its time set to 00:00:00.

From the java.sql.Date doc (italicized text is mine)…

Class Date

java.lang.Object

    java.util.Date        ← Inherits from j.u.Date

        java.sql.Date

A thin wrapper around a millisecond value that allows JDBC to identify this as an SQL DATE value. A milliseconds value represents the number of milliseconds that have passed since January 1, 1970 00:00:00.000 GMT.  ← Time-of-day set to Zero, midnight GMT/UTC

To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.

Date-Only versus Date-Time

The core problem is:

  • SQL
    In SQL, the DATE data type stores a date-only, without a time-of-day.
  • JAVA
    In the badly designed date-time library bundled with the early versions of Java, they failed to include a class to represent a date-only.

Instead of creating a date-only class, the Java team made a terrible hack. They took their date-time class (the misnamed java.util.Date class, containing both date and time) and extended it to have an instance set its time-of-day to midnight UTC, 00:00:00. That hack, that subclass of j.u.Date, is java.sql.Date.

All this hacking, poor design, and misnaming has made a confusing mess.

Which To Use

So when to use which? Simple, after cutting through the confusion.

  • When reading or writing to a database’s date-only column, use java.sql.Date as it clumsily tries to mask its time-of-day.
  • Everywhere else in Java, where you need a time-of-day along with your date, use java.util.Date.
  • When you have a java.sql.Date in hand but need a java.util.Date, simply pass the java.sql.Date. As a subclass, a java.sql.Date is a java.util.Date.

Even Better

In modern Java, you now have a choice of decent date-time libraries to supplant the old and notoriously troublesome java.util.Date, Calendar, SimpleTextFormat, and java.sql.Date classes bundled with Java. The main choices are:

  • Joda-Time
  • java.time
    (inspired by Joda-Time, defined by JSR 310, bundled with Java 8, extended by the ThreeTen-Extra project)

Both offer a LocalDate class to represent a date only, with no time-of-day and no time zone.

A JDBC driver updated to JDBC 4.2 or later can be used to directly exchange java.time objects with the database. Then we can completely abandon the ugly mess that is the date-time classes in the java.util.* and java.sql.* packages.

setObject | getObject

This article published by Oracle explains that the JDBC in Java 8 has been updated transparently to map a SQL DATE value to the new java.time.LocalDate type if you call getObject and setObject methods.

In obtuse language, the bottom of the JDBC 4.2 update spec confirms that article, with new mappings added to the getObject and setObject methods.

myPreparedStatement.setObject( … , myLocalDate ) ;

…and…

LocalDate myLocalDate = myResultSet.getObject( … , LocalDate.class ) ;

Convert

The spec also says new methods have been added to the java.sql.Date class to convert back and forth to java.time.LocalDate.

  • public java.time.instant toInstant()
  • public java.time.LocalDate toLocalDate()
  • public static java.sql.Date valueOf(java.time.LocalDate)

Time Zone

The old java.util.Date, java.sql.Date, and java.sql.Timestamp are always in UTC. The first two (at least) have a time zone buried deep in their source code but is used only under-the-surface such as the equals method, and has no getter/setter.

More confusingly, their toString methods apply the JVM’s current default time zone. So to the naïve programmer it seems like they have a time zone but they do not.

Both the buried time zone and the toString behavior are two of many reasons to avoid these troublesome old legacy classes.

Write your business logic using java.time (Java 8 and later). Where java.time lacks, use Joda-Time. Both java.time and Joda-Time have convenient methods for going back and forth with the old classes where need be.

Replacements:

  • java.util.Date is replaced by java.time.Instant
  • java.sql.Timestamp is replaced by java.time.Instant
  • java.sql.Date is replaced by java.time.LocalDate.
  • java.sql.Time is replaced by java.time.LocalTime.

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).

All three java.time.Local… classes are all lacking any concept of time zone or offset-from-UTC.


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?

  • Java SE 8, Java SE 9, Java SE 10, and later

    • Built-in.
    • 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
    • Much 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….

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.

Good way for Java Date comparison without time

The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.

  • For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
  • If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Learn about the modern date-time API from Trail: Date Time.

LocalDate uses JVM's timezone by default

Whenever timezone is involved, make sure to specify the same while creating an instance of LocalDate. A LocalDate uses JVM's timezone by default and you should never compare a LocalDate from one timezone to that of another without converting both of them in the same timezone (the recommended one is UTC). Same is the case with LocalDateTime. Instead of using LocalDate, you should do all processing with objects which have both date and time (e.g. LocalDateTime) and if required you can derive the LocalDate from them.

Also, the java.util.Date object simply represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). When you print an object of java.util.Date, its toString method returns the date-time in the JVM's timezone, calculated from this milliseconds value.

Therefore, if you are deriving expiryDate from a java.util.Date object, it is essentially date-time in UTC.

You can convert now-in-PST and expiryDate into java.time.Instant and compare them. A java.time.Instant is an instantaneous point on the UTC time-line.

Demo using the modern date-time API:

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;

public class Main {
public static void main(String[] args) {
LocalDateTime nowInPST = LocalDateTime.now(ZoneId.of("America/Los_Angeles"));
System.out.println(nowInPST);

// Convert it to date in UTC
Instant nowInPSTConvertedToInstant = nowInPST.atZone(ZoneId.of("America/Los_Angeles"))
.withZoneSameInstant(ZoneId.of("Etc/UTC"))
.toInstant();

// Some java.util.Date
Calendar calendar = Calendar.getInstance();
calendar.set(2020, 0, 10, 10, 10, 10);
Date date = calendar.getTime();
Instant expiry = date.toInstant();

System.out.println(nowInPSTConvertedToInstant.isBefore(expiry));
}
}

Output:

2021-01-17T10:58:38.490041
false

Note: Check the following notice at the Home Page of Joda-Time

Joda-Time is the de facto standard date and time library for Java
prior to Java SE 8. Users are now asked to migrate to java.time
(JSR-310).

Simplify your expression

The following statement

boolean notExpired = expiryDate.isEqual(now) || expiryDate.isAfter(now);

can be simplified as

boolean notExpired = !expiryDate.isBefore(now);


Related Topics



Leave a reply



Submit