1. The Hook (The "Byte-Sized" Intro)
- In a Nutshell: java.time (Java 8) replaces legacy Date/Calendar—immutable, thread-safe, clear! Key classes: LocalDate (date only), LocalTime (time only), LocalDateTime (date+time), ZonedDateTime (with timezone), Instant (timestamp), Duration (time-based period), Period (date-based period), DateTimeFormatter (parsing/formatting). Immutable = thread-safe. Fluent API = chainable methods.
- No more: mutable dates, confusing month indexing (0-11), poor timezone support!
Think of calendar evolution. Old Date = paper calendar (tear off pages, messy corrections, confusing). New java.time = digital calendar (immutable, clear zones, precise calculations). Can't accidentally modify "March 3rd" into "April 3rd"—create new date instead!
2. Conceptual Clarity (The "Simple" Tier)
💡 The Analogy
- LocalDate: Calendar page (just the date, no time)
- LocalTime: Clock face (just the time, no date)
- LocalDateTime: Calendar + clock (date and time, no timezone)
- ZonedDateTime: World clock (date/time/timezone)
- Instant: Timestamp machine (milliseconds since epoch)
Date/Time Class Hierarchy
graph TD
A[java.time API] --> B[LocalDate<br/>2024-03-15]
A --> C[LocalTime<br/>14:30:00]
A --> D[LocalDateTime<br/>2024-03-15T14:30]
A --> E[ZonedDateTime<br/>2024-03-15T14:30-05:00]
A --> F[Instant<br/>Epoch milliseconds]
G[Periods] --> H[Duration<br/>Time-based]
G --> I[Period<br/>Date-based]
3. Technical Mastery (The "Deep Dive")
Core Classes
| Class | Contains | Example | Use When |
|---|---|---|---|
| LocalDate | Date only | 2024-03-15 | Birthdays, holidays |
| LocalTime | Time only | 14:30:00 | Opening hours |
| LocalDateTime | Date + time | 2024-03-15T14:30 | Logs, timestamps (no zone) |
| ZonedDateTime | Date + time + zone | 2024-03-15T14:30-05:00 | International apps |
| Instant | Machine time | Epoch milliseconds | Precise timestamps |
| Duration | Time period | 5 hours 30 minutes | Time differences |
| Period | Date period | 2 years 3 months | Age calculations |
4. Interactive & Applied Code
java
import java.time.*;
import java.time.format.*;
import java.time.temporal.*;
public class DateTimeAPIDemo {
public static void main(String[] args) {
demonstrateLocalDate();
demonstrateLocalTime();
demonstrateLocalDateTime();
demonstrateZonedDateTime();
demonstrateInstant();
demonstrateDurationPeriod();
demonstrateFormatting();
}
// LocalDate (date only)
static void demonstrateLocalDate() {
System.out.println("=== LOCAL DATE ===");
// Creating
LocalDate today = LocalDate.now();
LocalDate specific = LocalDate.of(2024, 3, 15);
LocalDate parsed = LocalDate.parse("2024-03-15");
System.out.println("Today: " + today);
System.out.println("Specific: " + specific);
// Arithmetic (returns new instance - immutable!)
LocalDate tomorrow = today.plusDays(1);
LocalDate nextWeek = today.plusWeeks(1);
LocalDate nextMonth = today.plusMonths(1);
LocalDate nextYear = today.plusYears(1);
System.out.println("Tomorrow: " + tomorrow);
System.out.println("Next week: " + nextWeek);
// Extracting components
int year = today.getYear();
Month month = today.getMonth();
int day = today.getDayOfMonth();
DayOfWeek dayOfWeek = today.getDayOfWeek();
System.out.println("Year: " + year + ", Month: " + month + ", Day: " + day);
System.out.println("Day of week: " + dayOfWeek);
}
// LocalTime (time only)
static void demonstrateLocalTime() {
System.out.println("\n=== LOCAL TIME ===");
LocalTime now = LocalTime.now();
LocalTime specific = LocalTime.of(14, 30, 0);
LocalTime parsed = LocalTime.parse("14:30:00");
System.out.println("Now: " + now);
System.out.println("Specific: " + specific);
// Arithmetic
LocalTime later = now.plusHours(2);
LocalTime earlier = now.minusMinutes(30);
System.out.println("2 hours later: " + later);
System.out.println("30 mins earlier: " + earlier);
}
// LocalDateTime (date + time)
static void demonstrateLocalDateTime() {
System.out.println("\n=== LOCAL DATE TIME ===");
LocalDateTime now = LocalDateTime.now();
LocalDateTime specific = LocalDateTime.of(2024, 3, 15, 14, 30, 0);
// Combining LocalDate and LocalTime
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.of(14, 30);
LocalDateTime combined = LocalDateTime.of(date, time);
System.out.println("Combined: " + combined);
// Arithmetic
LocalDateTime future = now.plusDays(5).plusHours(3);
System.out.println("5 days + 3 hours from now: " + future);
}
// ZonedDateTime (with timezone)
static void demonstrateZonedDateTime() {
System.out.println("\n=== ZONED DATE TIME ===");
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime tokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
ZonedDateTime ny = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println("Local: " + now);
System.out.println("Tokyo: " + tokyo);
System.out.println("New York: " + ny);
// Convert between zones
ZonedDateTime tokyoTime = now.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
System.out.println("Local time in Tokyo: " + tokyoTime);
}
// Instant (machine time - epoch milliseconds)
static void demonstrateInstant() {
System.out.println("\n=== INSTANT ===");
Instant now = Instant.now();
Instant epoch = Instant.ofEpochMilli(0);
System.out.println("Now: " + now);
System.out.println("Epoch: " + epoch);
System.out.println("Epoch seconds: " + now.getEpochSecond());
// Arithmetic
Instant later = now.plusSeconds(3600); // 1 hour later
System.out.println("1 hour later: " + later);
}
// Duration (time-based) and Period (date-based)
static void demonstrateDurationPeriod() {
System.out.println("\n=== DURATION & PERIOD ===");
// Duration (for time)
LocalTime start = LocalTime.of(9, 0);
LocalTime end = LocalTime.of(17, 30);
Duration workDay = Duration.between(start, end);
System.out.println("Work duration: " + workDay.toHours() + " hours " +
(workDay.toMinutes() % 60) + " minutes");
// Period (for dates)
LocalDate birthDate = LocalDate.of(1990, 1, 15);
LocalDate today = LocalDate.now();
Period age = Period.between(birthDate, today);
System.out.println("Age: " + age.getYears() + " years " +
age.getMonths() + " months " +
age.getDays() + " days");
// Duration arithmetic
Instant now = Instant.now();
Instant future = now.plus(Duration.ofHours(5));
System.out.println("5 hours from now: " + future);
}
// Formatting and Parsing
static void demonstrateFormatting() {
System.out.println("\n=== FORMATTING ===");
LocalDateTime now = LocalDateTime.now();
// Predefined formatters
String iso = now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
System.out.println("ISO: " + iso);
// Custom patterns
DateTimeFormatter custom = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = now.format(custom);
System.out.println("Custom: " + formatted);
// Parsing
LocalDateTime parsed = LocalDateTime.parse("2024-03-15 14:30:00", custom);
System.out.println("Parsed: " + parsed);
// Localized
DateTimeFormatter french = DateTimeFormatter.ofPattern("EEEE dd MMMM yyyy",
java.util.Locale.FRENCH);
System.out.println("French: " + now.format(french));
}
}5. The Comparison & Decision Layer
| Old (Date/Calendar) | New (java.time) | Benefit |
|---|---|---|
| Mutable | Immutable | Thread-safe |
| Month 0-11 | Month 1-12 | Natural indexing |
| Poor timezone | ZonedDateTime | Clear timezone handling |
| Confusing API | Fluent API | Readable, chainable |
| Not thread-safe | Thread-safe | Concurrency-safe |
6. The "Interview Corner" (The Edge)
The "Killer" Interview Question: "Duration vs Period?" Answer:
- Duration: Time-based (hours, minutes, seconds)
- Period: Date-based (years, months, days)
java
// Duration: Time difference
LocalTime start = LocalTime.of(9, 0);
LocalTime end = LocalTime.of(17, 0);
Duration duration = Duration.between(start, end);
System.out.println(duration.toHours()); // 8 hours
// Period: Date difference
LocalDate birth = LocalDate.of(1990, 1, 1);
LocalDate today = LocalDate.now();
Period period = Period.between(birth, today);
System.out.println(period.getYears() + " years"); // 34 yearsPro-Tip: Immutability means all operations return NEW instances:
java
LocalDate date = LocalDate.of(2024, 3, 15);
// ❌ DOESN'T WORK: plusDays returns NEW instance!
date.plusDays(1); // date unchanged!
System.out.println(date); // Still 2024-03-15
// ✅ CORRECT: Capture returned value
LocalDate tomorrow = date.plusDays(1);
System.out.println(tomorrow); // 2024-03-16