Java Date and Time API (java.time): LocalDate, ZonedDateTime, Period & Duration
Welcome to Phase 20: Java Date and Time API (java.time) Masterclass! Prior to Java 8, handling dates and times in Java using legacy java.util.Date and java.util.Calendar was notoriously error-prone, mutable, and thread-unsafe. Java 8 introduced the modern JSR-310 java.time package, designed from the ground up to be immutable, thread-safe, domain-driven, and ISO-8601 compliant. In this comprehensive in-depth guide, you will master LocalDate, LocalTime, LocalDateTime, ZonedDateTime, DateTimeFormatter for formatting and parsing, date math, date comparisons, the crucial difference between Period and Duration, and global time zone conversions.
โ ๏ธ The 4 Major Flaws of Legacy java.util.Date & Calendar:
1. Mutability (Thread-Unsafe): Date objects are mutable (e.g. date.setTime(...)). Two threads sharing a date object cause race conditions!
2. Confusing 0-Indexed Months: January is 0 and December is 11! (Passing 12 rolled over to January next year). Years started from 1900!
3. SimpleDateFormat is NOT Thread-Safe: Using a shared SimpleDateFormat in multi-threaded Spring Boot backends corrupted timestamps.
4. No Domain Separation: java.util.Date represented both Date and Time combined, even when only a date (e.g. Birthday) was needed.
Modern Class (java.time) | Domain Meaning | Contains Timezone? | Example Representation |
|---|---|---|---|
LocalDate | Date Only (Year, Month, Day) | No | 2026-08-17 (Birthdays, Holidays) |
LocalTime | Time Only (Hour, Min, Sec, Nano) | No | 14:30:45.123 (Store opening hours) |
LocalDateTime | Date + Time combined | No | 2026-08-17T14:30:45 (Scheduled Meeting) |
ZonedDateTime | Date + Time + ZoneId | Yes | 2026-08-17T14:30:45+05:30[Asia/Kolkata] |
Instant | Machine Timestamp (Epoch Seconds) | UTC | 2026-08-17T09:00:45Z (Database Audit Logs) |
Modern date-time classes provide clear factory constructors (now(), of()) and getter methods:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.time.Month;
public class DateTimeBasicsDemo {
public static void main(String[] args) {
// 1. LocalDate (Date only)
LocalDate today = LocalDate.now();
LocalDate independenceDay = LocalDate.of(1947, Month.AUGUST, 15);
System.out.println("Today's Date: " + today);
System.out.println("Year: " + today.getYear() + " | Month: " + today.getMonth() + " | Day: " + today.getDayOfMonth());
// 2. LocalTime (Time only)
LocalTime currentTime = LocalTime.now();
LocalTime meetingTime = LocalTime.of(10, 30, 0); // 10:30 AM
System.out.println("Current Time: " + currentTime);
// 3. LocalDateTime (Date + Time)
LocalDateTime currentDateTime = LocalDateTime.now();
LocalDateTime newYear2027 = LocalDateTime.of(2027, 1, 1, 0, 0, 0);
System.out.println("New Year: " + newYear2027);
}
}
DateTimeFormatter is completely immutable and thread-safe. It converts dates to custom formatted strings and parses input strings into date objects:
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class FormattingAndParsingDemo {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
// 1. Formatting Date -> Custom String
DateTimeFormatter customFormat = DateTimeFormatter.ofPattern("dd-MM-yyyy hh:mm:ss a");
String formattedOutput = now.format(customFormat);
System.out.println("Formatted Indian Timestamp: " + formattedOutput);
// 2. Parsing String -> LocalDate
String userInputDate = "25/12/2026";
DateTimeFormatter inputParser = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate parsedChristmas = LocalDate.parse(userInputDate, inputParser);
System.out.println("Parsed Date: " + parsedChristmas + " (Day of week: " + parsedChristmas.getDayOfWeek() + ")");
}
}
Because java.time objects are immutable, math operations return a new updated instance without modifying the original:
import java.time.LocalDate;
public class DateArithmeticDemo {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
// 1. Adding and Subtracting
LocalDate nextWeek = today.plusDays(7);
LocalDate threeMonthsAgo = today.minusMonths(3);
LocalDate nextYear = today.plusYears(1);
System.out.println("Today: " + today);
System.out.println("1 Week Later: " + nextWeek);
System.out.println("3 Months Ago: " + threeMonthsAgo);
// 2. Comparing Dates (isBefore, isAfter, isEqual)
LocalDate expiryDate = LocalDate.of(2026, 12, 31);
if (today.isBefore(expiryDate)) {
System.out.println("โ
Product license is ACTIVE.");
} else {
System.out.println("โ Product license has EXPIRED.");
}
}
}
๐ก Period vs Duration โ Must-Know Interview Distinction
โข Period (Date-Based): Measures difference in Years, Months, and Days (e.g. Age calculation between two LocalDate instances).
โข Duration (Time-Based): Measures difference in Seconds, Milliseconds, and Nanoseconds (e.g. Measuring execution time benchmark between two LocalTime or Instant instances).
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.Duration;
public class PeriodDurationDemo {
public static void main(String[] args) {
// 1. Period: Age Calculator
LocalDate birthDate = LocalDate.of(2000, 5, 15);
LocalDate today = LocalDate.now();
Period age = Period.between(birthDate, today);
System.out.println("Exact Age: " + age.getYears() + " Years, " +
age.getMonths() + " Months, and " + age.getDays() + " Days.");
// 2. Duration: Benchmark Execution Time
LocalTime startTime = LocalTime.of(10, 15, 30);
LocalTime endTime = LocalTime.of(12, 45, 50);
Duration taskDuration = Duration.between(startTime, endTime);
System.out.println("Task Duration: " + taskDuration.toHours() + " hours and " +
(taskDuration.toMinutes() % 60) + " minutes (" + taskDuration.toSeconds() + " total seconds).");
}
}
International applications and flight ticketing systems require exact time zone awareness via ZoneId:
import java.time.ZonedDateTime;
import java.time.ZoneId;
public class TimeZoneDemo {
public static void main(String[] args) {
// Current Time in India (IST)
ZoneId istZone = ZoneId.of("Asia/Kolkata");
ZonedDateTime indiaTime = ZonedDateTime.now(istZone);
System.out.println("India Time (IST): " + indiaTime);
// Convert Same Instant to New York (EST) & Tokyo (JST)
ZonedDateTime newYorkTime = indiaTime.withZoneSameInstant(ZoneId.of("America/New_York"));
ZonedDateTime tokyoTime = indiaTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
System.out.println("New York Time (EST): " + newYorkTime);
System.out.println("Tokyo Time (JST): " + tokyoTime);
}
}
Run this complete date and time formatter in our online Java compiler:
import java.time.LocalDate;
import java.time.Period;
public class Main {
public static void main(String[] args) {
LocalDate start = LocalDate.of(2024, 1, 1);
LocalDate current = LocalDate.now();
Period period = Period.between(start, current);
System.out.println("Time elapsed since Jan 1, 2024: " +
period.getYears() + " years, " + period.getMonths() + " months, " + period.getDays() + " days.");
}
}