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/CalendarAPI - The new key classes:
LocalDate,LocalTime,LocalDateTime,ZonedDateTime - Formatting dates with
DateTimeFormatter - Calculating differences with
PeriodandDuration - 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:
Datealso 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:
| Class | What it represents |
|---|---|
LocalDate | Date only (year, month, day) โ no time, no timezone |
LocalTime | Time only (hour, minute, second, nanosecond) |
LocalDateTime | Date + Time, no timezone |
ZonedDateTime | Date + Time + Timezone |
Instant | A point in time (like a timestamp) |
Period | Amount of time in years/months/days |
Duration | Amount of time in hours/minutes/seconds/nanoseconds |
DateTimeFormatter | Format/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()orCalendarin new code โ โ Fix: Always use the newjava.timeAPI โ it's cleaner, immutable, and thread-safe - โ Mistake: Confusing
PeriodandDurationโ โ Fix:Periodis for date differences (days/months/years);Durationis 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.timeobjects are immutable โdate.plusDays(1)doesn't changedateโ โ Fix: Always assign the result:date = date.plusDays(1) - โ Mistake: Using wrong pattern letter in
DateTimeFormatter(e.g.,YYYYinstead ofyyyy) โ โ Fix:yyyy= calendar year,YYYY= week-based year โ useyyyyfor standard dates
Best Practicesโ
- Use
LocalDatewhen you only care about the date (no time component needed) - Use
LocalDateTimefor date + time but no timezone; useZonedDateTimefor timezone-aware apps - Always use
DateTimeFormatter.ofPattern()to format โ don't string-concatenate date parts manually - Store dates as
LocalDate/LocalDateTimein 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
Related Topicsโ
- 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)