Skip to main content

Date and Time API

Reading Time: 10 Minutes
Difficulty: Beginner


Topic Summaryโ€‹

Java 8 introduced a completely new Date and Time API (java.time package) to replace the old, buggy java.util.Date and java.util.Calendar classes. The new API is immutable, thread-safe, and much easier to understand. You can now work with dates and times clearly without confusion about month indexing or time zones.


What You'll Learnโ€‹

  • What was wrong with the old Date/Calendar API
  • The new key classes: LocalDate, LocalTime, LocalDateTime, ZonedDateTime
  • Formatting dates with DateTimeFormatter
  • Calculating differences with Period and Duration
  • Practical examples: age calculator, days between dates

Prerequisitesโ€‹

  • Basic Java (classes, methods)
  • No special prerequisites

Explanationโ€‹

What Was Wrong with the Old API?โ€‹

The old java.util.Date and java.util.Calendar had several problems:

  • Month indexing starts at 0: January = 0, December = 11 โ€” constant source of bugs
  • Not immutable: Date objects could be modified โ€” dangerous in multi-threaded apps
  • Not thread-safe: Multiple threads accessing a Calendar was problematic
  • Poor design: Date also stores time, but the name implies only date โ€” confusing
  • Time zones: Handling was a nightmare with the old API
// Old API โ€” confusing and error-prone
Calendar cal = Calendar.getInstance();
cal.set(2024, 0, 15); // January is 0, not 1! Easy to get wrong
Date date = cal.getTime();

The New java.time Packageโ€‹

Java 8's new API is in java.time. Key classes:

ClassWhat it represents
LocalDateDate only (year, month, day) โ€” no time, no timezone
LocalTimeTime only (hour, minute, second, nanosecond)
LocalDateTimeDate + Time, no timezone
ZonedDateTimeDate + Time + Timezone
InstantA point in time (like a timestamp)
PeriodAmount of time in years/months/days
DurationAmount of time in hours/minutes/seconds/nanoseconds
DateTimeFormatterFormat/parse date-time objects

LocalDateโ€‹

LocalDate = date without time. Most common for business logic.

// Get today's date
LocalDate today = LocalDate.now();

// Specific date
LocalDate birthday = LocalDate.of(2000, 3, 15); // March 15, 2000
// Month enum is cleaner:
LocalDate birthday = LocalDate.of(2000, Month.MARCH, 15);

// Accessing parts
int year = today.getYear();
Month month = today.getMonth(); // JANUARY, FEBRUARY...
int monthValue = today.getMonthValue(); // 1-12 (not 0-11!)
int day = today.getDayOfMonth();
DayOfWeek dow = today.getDayOfWeek(); // MONDAY, TUESDAY...

// Arithmetic
LocalDate nextWeek = today.plusDays(7);
LocalDate lastMonth = today.minusMonths(1);
LocalDate nextYear = today.plusYears(1);

LocalTimeโ€‹

LocalTime = time without date.

LocalTime now = LocalTime.now();
LocalTime noon = LocalTime.of(12, 0, 0); // 12:00:00
LocalTime meeting = LocalTime.of(14, 30); // 14:30

int hour = now.getHour();
int minute = now.getMinute();

LocalTime later = now.plusHours(2);
LocalTime earlier = now.minusMinutes(30);

LocalDateTimeโ€‹

LocalDateTime = date + time, no timezone.

LocalDateTime now = LocalDateTime.now();
LocalDateTime event = LocalDateTime.of(2025, 12, 25, 18, 0); // Christmas at 6 PM

// Combine LocalDate and LocalTime
LocalDate date = LocalDate.of(2025, 1, 1);
LocalTime time = LocalTime.of(9, 30);
LocalDateTime dt = LocalDateTime.of(date, time);

ZonedDateTimeโ€‹

ZonedDateTime = date + time + timezone.

ZonedDateTime nowIndia = ZonedDateTime.now(ZoneId.of("Asia/Kolkata"));
ZonedDateTime nowNY = ZonedDateTime.now(ZoneId.of("America/New_York"));

// Convert between zones
ZonedDateTime converted = nowIndia.withZoneSameInstant(ZoneId.of("America/New_York"));

DateTimeFormatterโ€‹

Format and parse date-time objects as strings.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate date = LocalDate.of(2025, 3, 15);

// Format date โ†’ String
String formatted = date.format(formatter); // "15-03-2025"

// Parse String โ†’ date
LocalDate parsed = LocalDate.parse("15-03-2025", formatter);

// Built-in formatters
String iso = date.format(DateTimeFormatter.ISO_LOCAL_DATE); // "2025-03-15"

Period โ€” Date Differencesโ€‹

Period measures time in years, months, and days (between dates).

LocalDate birthDate = LocalDate.of(2000, 5, 20);
LocalDate today = LocalDate.now();

Period age = Period.between(birthDate, today);
System.out.println("Age: " + age.getYears() + " years, "
+ age.getMonths() + " months, " + age.getDays() + " days");

Duration โ€” Time Differencesโ€‹

Duration measures time in hours, minutes, seconds (between times/datetimes).

LocalTime start = LocalTime.of(9, 0);
LocalTime end = LocalTime.of(17, 30);

Duration workDay = Duration.between(start, end);
System.out.println("Work hours: " + workDay.toHours()); // 8
System.out.println("Work minutes: " + workDay.toMinutes()); // 510

Real-World Analogyโ€‹

The old Date API was like a Swiss Army knife with no labels โ€” confusing, everything was in one messy tool. The new java.time API is like a professional toolkit where every tool has a clear purpose: LocalDate is your calendar page, LocalTime is your clock, LocalDateTime is your appointment diary, ZonedDateTime is an international meeting scheduler.


Code Exampleโ€‹

Example 1: Age Calculatorโ€‹

import java.time.*;

public class AgeCalculator {
public static void main(String[] args) {
// Birth date
LocalDate birthDate = LocalDate.of(2000, 8, 15);
LocalDate today = LocalDate.now();

// Calculate age using Period
Period age = Period.between(birthDate, today);
System.out.println("Birth Date: " + birthDate);
System.out.println("Today: " + today);
System.out.println("Age: " + age.getYears() + " years, "
+ age.getMonths() + " months, "
+ age.getDays() + " days");

// Days until next birthday
LocalDate nextBirthday = birthDate.withYear(today.getYear());
if (nextBirthday.isBefore(today) || nextBirthday.isEqual(today)) {
nextBirthday = nextBirthday.plusYears(1);
}
long daysUntilBirthday = nextBirthday.toEpochDay() - today.toEpochDay();
System.out.println("Days until next birthday: " + daysUntilBirthday);
}
}

Output (approximate)โ€‹

Birth Date: 2000-08-15
Today: 2025-06-28
Age: 24 years, 10 months, 13 days
Days until next birthday: 48

Example 2: Days Between Dates and Formattingโ€‹

import java.time.*;
import java.time.format.*;
import java.time.temporal.ChronoUnit;

public class DateTimeFormatting {
public static void main(String[] args) {
// Different formatters
LocalDate date = LocalDate.of(2025, 12, 25);
DateTimeFormatter f1 = DateTimeFormatter.ofPattern("dd/MM/yyyy");
DateTimeFormatter f2 = DateTimeFormatter.ofPattern("MMMM dd, yyyy");
DateTimeFormatter f3 = DateTimeFormatter.ofPattern("EEE, MMM d yyyy");

System.out.println(date.format(f1)); // 25/12/2025
System.out.println(date.format(f2)); // December 25, 2025
System.out.println(date.format(f3)); // Thu, Dec 25 2025

// Parse a date string
String dateStr = "28-06-2025";
LocalDate parsed = LocalDate.parse(dateStr,
DateTimeFormatter.ofPattern("dd-MM-yyyy"));
System.out.println("Parsed: " + parsed); // 2025-06-28

// Days between two dates
LocalDate from = LocalDate.of(2025, 1, 1);
LocalDate to = LocalDate.of(2025, 12, 31);
long daysBetween = ChronoUnit.DAYS.between(from, to);
System.out.println("Days in 2025: " + daysBetween); // 364

// LocalDateTime formatting
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dtFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println("Now: " + now.format(dtFormatter));
}
}

Outputโ€‹

25/12/2025
December 25, 2025
Thu, Dec 25 2025
Parsed: 2025-06-28
Days in 2025: 364
Now: 2025-06-28 13:45:22

Example 3: Duration and Time Zonesโ€‹

import java.time.*;

public class DurationAndZones {
public static void main(String[] args) {
// Duration โ€” work hours
LocalTime workStart = LocalTime.of(9, 0);
LocalTime workEnd = LocalTime.of(18, 30);
Duration workDuration = Duration.between(workStart, workEnd);
System.out.println("Work duration: " + workDuration.toHours() + "h "
+ (workDuration.toMinutesPart()) + "m"); // 9h 30m

// Time zones
ZoneId indiaZone = ZoneId.of("Asia/Kolkata");
ZoneId nyZone = ZoneId.of("America/New_York");

ZonedDateTime indiaTime = ZonedDateTime.now(indiaZone);
ZonedDateTime nyTime = indiaTime.withZoneSameInstant(nyZone);

System.out.println("India time: " + indiaTime.toLocalTime());
System.out.println("New York time: " + nyTime.toLocalTime());
}
}

Outputโ€‹

Work duration: 9h 30m
India time: 13:45:22
New York time: 04:15:22

Common Mistakesโ€‹

  • โŒ Mistake: Using new Date() or Calendar in new code โ†’ โœ… Fix: Always use the new java.time API โ€” it's cleaner, immutable, and thread-safe
  • โŒ Mistake: Confusing Period and Duration โ†’ โœ… Fix: Period is for date differences (days/months/years); Duration is for time differences (hours/minutes/seconds)
  • โŒ Mistake: Thinking LocalDate.now() returns a different value each time it's called in the same second โ†’ โœ… Fix: It does return today's date โ€” just note it depends on system clock
  • โŒ Mistake: Forgetting that all java.time objects are immutable โ€” date.plusDays(1) doesn't change date โ†’ โœ… Fix: Always assign the result: date = date.plusDays(1)
  • โŒ Mistake: Using wrong pattern letter in DateTimeFormatter (e.g., YYYY instead of yyyy) โ†’ โœ… Fix: yyyy = calendar year, YYYY = week-based year โ€” use yyyy for standard dates

Best Practicesโ€‹

  • Use LocalDate when you only care about the date (no time component needed)
  • Use LocalDateTime for date + time but no timezone; use ZonedDateTime for timezone-aware apps
  • Always use DateTimeFormatter.ofPattern() to format โ€” don't string-concatenate date parts manually
  • Store dates as LocalDate/LocalDateTime in code; convert to string only for display
  • Use ChronoUnit.DAYS.between(d1, d2) for simple day-count differences

Interview Questionsโ€‹

Q: What problems did the old Java Date API have?
A: Months were 0-indexed (January = 0), Date was mutable and not thread-safe, date and time were mixed in one class, and timezone handling was confusing. Calendar was overly complex. The new java.time API in Java 8 fixed all of these issues.

Q: What is the difference between LocalDate, LocalDateTime, and ZonedDateTime?
A: LocalDate has only date (year, month, day). LocalDateTime has date and time but no timezone. ZonedDateTime has date, time, and timezone information. Use the simplest one that meets your needs.

Q: What is the difference between Period and Duration?
A: Period represents an amount of time in date units (years, months, days) and is used between two LocalDate objects. Duration represents time in seconds and nanoseconds (hours, minutes, seconds) and is used between LocalTime or LocalDateTime objects.

Q: How do you format a LocalDate to a string in Java 8?
A: Use DateTimeFormatter.ofPattern("your-pattern") and call date.format(formatter). For example: date.format(DateTimeFormatter.ofPattern("dd-MM-yyyy")).


Quick Revisionโ€‹

โœ” Old Date API: mutable, months 0-indexed, not thread-safe
โœ” LocalDate = date only; LocalTime = time only; LocalDateTime = both; ZonedDateTime = with timezone
โœ” All java.time objects are immutable โ€” operations return new objects
โœ” Period.between(d1, d2) = date difference in years/months/days
โœ” Duration.between(t1, t2) = time difference in hours/minutes/seconds
โœ” DateTimeFormatter.ofPattern("dd-MM-yyyy") for formatting/parsing


  • Java 8 Stream API
  • Optional Class
  • Immutable Objects in Java
  • Java Threads and Thread Safety

Next Lessonโ€‹

Lesson 8 โ€” var Keyword (Local Variable Type Inference)