00:00

Date Class in Java – java.util.Date and the Modern java.time API

java.util.Date represents a specific instant in time, stored as the number of milliseconds since 1 January 1970, 00:00:00 UTC (the Unix epoch). It has been part of Java since version 1.0 and still appears in older code and APIs such as JDBC and many libraries.

Most of Date's methods are deprecated, and since Java 8 the java.time API (LocalDate, LocalDateTime, ZonedDateTime, Instant) is the recommended replacement. This tutorial shows how to use Date, explains its problems, and shows the modern equivalents and conversions.

1. Creating, Formatting and Comparing Dates

DateBasics.java
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class DateBasics {
    public static void main(String[] args) throws Exception {
        Date now = new Date();                                   // current instant
        System.out.println("new Date() is close to currentTimeMillis: "
                + (Math.abs(now.getTime() - System.currentTimeMillis()) < 1000));

        Date launch = new Date(1_791_000_000_000L);              // milliseconds since 1970-01-01T00:00Z
        System.out.println("getTime()      : " + launch.getTime());

        SimpleDateFormat fmt = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss zzz", Locale.ENGLISH);
        fmt.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));   // Date has no time zone itself
        System.out.println("formatted (IST): " + fmt.format(launch));
        fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
        System.out.println("formatted (UTC): " + fmt.format(launch));

        SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd");
        parser.setTimeZone(TimeZone.getTimeZone("UTC"));
        Date d = parser.parse("2026-10-11");
        System.out.println("parsed millis  : " + d.getTime());

        System.out.println("before/after   : " + d.before(launch) + " / " + d.after(launch));
        System.out.println("compareTo      : " + d.compareTo(launch));
    }
}
Output
new Date() is close to currentTimeMillis: true
getTime()      : 1791000000000
formatted (IST): 03-10-2026 09:30:00 IST
formatted (UTC): 03-10-2026 04:00:00 UTC
parsed millis  : 1791676800000
before/after   : false / true
compareTo      : 1
  • new Date() captures the current instant; new Date(millis) a specific one.
  • A Date has no time zone. toString() uses the JVM's default zone, which is why the same instant shows different clock times in IST and UTC.
  • SimpleDateFormat formats and parses dates with patterns, but it is not thread-safe.
  • Compare with before, after, compareTo or getTime().

2. Useful Methods

MethodDescription
Date(), Date(long millis)Non-deprecated constructors
long getTime() / setTime(long)Milliseconds since the epoch
before(Date), after(Date), compareTo(Date)Comparison
toInstant(), Date.from(Instant)Conversion to and from java.time (Java 8)
getYear(), getMonth(), getDate(), getHours()…Deprecated; use Calendar or java.time

3. Problems with java.util.Date

DateProblems.java
import java.util.Date;

public class DateProblems {
    @SuppressWarnings("deprecation")
    public static void main(String[] args) {
        // 1. Confusing, deprecated constructor: year is offset from 1900, month is 0-based
        Date d = new Date(126, 9, 11);          // means 2026-10-11!
        System.out.println("getYear() = " + d.getYear() + ", getMonth() = " + d.getMonth());

        // 2. Mutable: anyone holding the reference can change it
        Date deadline = new Date(0);
        Date alias = deadline;
        alias.setTime(86_400_000L);             // one day later
        System.out.println("deadline changed through alias: " + (deadline.getTime() == 86_400_000L));
    }
}
Output
getYear() = 126, getMonth() = 9
deadline changed through alias: true
  • Confusing values: years are offset from 1900 and months start at 0.
  • Mutable: shared Date objects can be changed unexpectedly, so classes must make defensive copies.
  • Misleading name: it is an instant, not a calendar date, and has no time zone.
  • Not thread-safe helpers: SimpleDateFormat breaks when shared between threads.
  • Poor date arithmetic: adding days or months needs Calendar.

4. The Modern Alternative: java.time

The java.time package (JSR 310, Java 8) fixes all these issues. Its classes are immutable, thread-safe and clearly named:

ModernDateTime.java
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Locale;

public class ModernDateTime {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2026, 10, 11);                 // date only, immutable
        LocalDate due = date.plusDays(30);
        System.out.println("date + 30 days : " + due + " (" + due.getDayOfWeek() + ")");
        System.out.println("days between   : " + ChronoUnit.DAYS.between(date, due));

        LocalDateTime meeting = LocalDateTime.of(2026, 10, 11, 15, 30);
        ZonedDateTime ist = meeting.atZone(ZoneId.of("Asia/Kolkata"));
        System.out.println("IST            : " + ist);
        System.out.println("New York       : " + ist.withZoneSameInstant(ZoneId.of("America/New_York")));

        DateTimeFormatter f = DateTimeFormatter.ofPattern("dd MMM yyyy, hh:mm a", Locale.ENGLISH);
        System.out.println("formatted      : " + meeting.format(f));
        System.out.println("parsed         : " + LocalDate.parse("2026-12-25").getDayOfWeek());

        // Converting between legacy Date and java.time
        Instant instant = ist.toInstant();
        Date legacy = Date.from(instant);
        System.out.println("round trip     : " + legacy.toInstant().equals(instant));
    }
}
Output
date + 30 days : 2026-11-10 (TUESDAY)
days between   : 30
IST            : 2026-10-11T15:30+05:30[Asia/Kolkata]
New York       : 2026-10-11T06:00-04:00[America/New_York]
formatted      : 11 Oct 2026, 03:30 PM
parsed         : FRIDAY
round trip     : true
NeedLegacyjava.time
Instant on the timelineDateInstant
Date without time (birthday)Date / CalendarLocalDate
Date and time without zoneDateLocalDateTime
Date and time in a zoneCalendar + TimeZoneZonedDateTime
FormattingSimpleDateFormat (not thread-safe)DateTimeFormatter (thread-safe)
Amount of timeManual millisecond arithmeticDuration, Period

When an API still requires Date, convert at the boundary with Date.from(instant) and date.toInstant(). For JDBC, java.sql.Date and Timestamp can be replaced by LocalDate and LocalDateTime with modern drivers.

5. Summary

  • java.util.Date stores an instant as milliseconds since the epoch and has no time zone.
  • Format and parse it with SimpleDateFormat, which is not thread-safe.
  • It is mutable and most methods are deprecated.
  • Use java.time (LocalDate, ZonedDateTime, Instant) for new code and convert at API boundaries.

Related Tutorials