Date and Time API in Java
1. Problems with the Old Date API
Before Java 8, date and time handling relied on
java.util.Date and
java.util.Calendar. These classes had
severe design problems that caused bugs and confusion for years:
-
Mutable and not thread-safe —
Dateobjects can be changed after creation, causing bugs in shared or cached state. -
Poor API design — months in
Calendarare 0-indexed (January = 0, December = 11), years inDateare relative to 1900, and years inCalendarare used normally — two inconsistent conventions in the same API. -
No separation of concepts —
Daterepresents a point in time (timestamp) but is also used as a calendar date, with no clean way to represent just a date, just a time, or a date+time without a timezone. - Confusing timezone handling — mixing of local and UTC times leads to subtle off-by-hours bugs.
-
Formatting is not thread-safe —
SimpleDateFormatis stateful and must not be shared across threads.
// Old API — full of traps
import java.util.*;
public class OldDateProblems {
public static void main(String[] args) {
// java.util.Date — year is offset from 1900, month is 0-indexed!
Date d = new Date(2024 - 1900, 0, 15); // Jan 15, 2024
System.out.println("Old Date: " + d); // Confusing output
// java.util.Calendar — months still 0-indexed
Calendar cal = Calendar.getInstance();
cal.set(2024, Calendar.JANUARY, 15); // Must use constant or risk off-by-one
System.out.println("Year: " + cal.get(Calendar.YEAR));
System.out.println("Month: " + cal.get(Calendar.MONTH)); // 0 = January!
System.out.println("Day: " + cal.get(Calendar.DAY_OF_MONTH));
// Mutable — dangerous when shared
Date original = new Date();
Date copy = original; // not a copy — same reference
copy.setTime(0); // accidentally mutates 'original' too
System.out.println("original == copy? " + (original.getTime() == copy.getTime()));
}
}
Best practice: Avoid
java.util.Date and
java.util.Calendar in new code. Use
java.time classes introduced in Java
8 instead.
2. Overview of java.time Package
The java.time package (inspired by the
Joda-Time library) provides a clean, immutable, and thread-safe
date/time API. All objects are immutable —
operations return new instances rather than modifying existing
ones.
| Class | Represents | Example |
|---|---|---|
LocalDate |
Date without time or timezone | 2026-07-23 |
LocalTime |
Time without date or timezone | 14:30:00.000 |
LocalDateTime |
Date + time without timezone | 2026-07-23T14:30:00 |
ZonedDateTime |
Date + time + timezone | 2026-07-23T14:30:00-05:00[America/New_York] |
Instant |
Machine timestamp (epoch seconds) | 2026-07-23T19:30:00Z |
Duration |
Time-based amount (hours, minutes, seconds) | PT2H30M |
Period |
Date-based amount (years, months, days) | P1Y6M10D |
DateTimeFormatter |
Format/parse date-time strings | "dd-MM-yyyy HH:mm" |
Immutability: All
java.time classes are immutable and
thread-safe. Methods like
plusDays() return a
new object — the original is unchanged.
3. LocalDate
LocalDate represents a date (year,
month, day) without any time-of-day or timezone information. It is
ideal for representing birthdays, anniversaries, deadlines, or any
concept that is just a calendar date.
import java.time.*;
import java.time.temporal.ChronoUnit;
public class LocalDateDemo {
public static void main(String[] args) {
// Create LocalDate instances
LocalDate today = LocalDate.now(); // current date
LocalDate specific = LocalDate.of(2026, 7, 23); // July 23, 2026
LocalDate parsed = LocalDate.parse("2025-12-25"); // ISO-8601 string
System.out.println("Today: " + today);
System.out.println("Specific: " + specific);
System.out.println("Parsed: " + parsed);
// Accessing fields
System.out.println("Year: " + today.getYear());
System.out.println("Month: " + today.getMonth()); // JULY
System.out.println("MonthValue: " + today.getMonthValue()); // 7 (1-indexed!)
System.out.println("Day: " + today.getDayOfMonth());
System.out.println("DayOfWeek: " + today.getDayOfWeek()); // WEDNESDAY
System.out.println("DayOfYear: " + today.getDayOfYear());
System.out.println("IsLeapYear: " + today.isLeapYear());
// Arithmetic — returns new instances (immutable)
LocalDate nextWeek = today.plusDays(7);
LocalDate prevMonth = today.minusMonths(1);
LocalDate nextYear = today.plusYears(1);
System.out.println("Next week: " + nextWeek);
System.out.println("Prev month: " + prevMonth);
System.out.println("Next year: " + nextYear);
// Comparison
LocalDate date1 = LocalDate.of(2024, 1, 1);
LocalDate date2 = LocalDate.of(2025, 6, 15);
System.out.println("date1 isBefore date2? " + date1.isBefore(date2));
System.out.println("date2 isAfter date1? " + date2.isAfter(date1));
System.out.println("Same date? " + date1.isEqual(date1));
// Days between two dates
long daysBetween = ChronoUnit.DAYS.between(date1, date2);
System.out.println("Days between: " + daysBetween);
}
}
Specific: 2026-07-23
Parsed: 2025-12-25
Year: 2026
Month: JULY
MonthValue: 7
Day: 23
DayOfWeek: THURSDAY
DayOfYear: 204
IsLeapYear: false
Next week: 2026-07-30
Prev month: 2026-06-23
Next year: 2027-07-23
date1 isBefore date2? true
date2 isAfter date1? true
Same date? true
Days between: 531
4. LocalTime
LocalTime represents a time-of-day
(hour, minute, second, nanosecond) without any date or timezone.
It is useful for representing opening hours, alarm times, or any
recurring daily time.
import java.time.*;
public class LocalTimeDemo {
public static void main(String[] args) {
// Create LocalTime instances
LocalTime now = LocalTime.now(); // current time
LocalTime noon = LocalTime.of(12, 0); // 12:00:00
LocalTime precise = LocalTime.of(14, 30, 45, 500000000); // 14:30:45.5
LocalTime parsed = LocalTime.parse("08:15:30");
System.out.println("Now: " + now);
System.out.println("Noon: " + noon);
System.out.println("Precise: " + precise);
System.out.println("Parsed: " + parsed);
// Accessing fields
System.out.println("Hour: " + now.getHour());
System.out.println("Minute: " + now.getMinute());
System.out.println("Second: " + now.getSecond());
System.out.println("Nano: " + now.getNano());
// Arithmetic
LocalTime twoHoursLater = noon.plusHours(2);
LocalTime thirtyMinEarlier = noon.minusMinutes(30);
System.out.println("Noon + 2h: " + twoHoursLater);
System.out.println("Noon - 30min: " + thirtyMinEarlier);
// Comparison
System.out.println("noon isBefore precise? " + noon.isBefore(precise));
System.out.println("noon isAfter parsed? " + noon.isAfter(parsed));
// Truncation — useful for ignoring sub-second precision
LocalTime truncated = now.withNano(0).withSecond(0); // floor to minute
System.out.println("Truncated to minute: " + truncated);
// Constants
System.out.println("Midnight: " + LocalTime.MIDNIGHT); // 00:00
System.out.println("Noon: " + LocalTime.NOON); // 12:00
}
}
Noon: 12:00
Precise: 14:30:45.500
Parsed: 08:15:30
Hour: 14
Minute: 30
Second: 22
Nano: 847000000
Noon + 2h: 14:00
Noon - 30min: 11:30
noon isBefore precise? true
noon isAfter parsed? true
Truncated to minute: 14:30
Midnight: 00:00
Noon: 12:00
5. LocalDateTime
LocalDateTime combines a date and a
time in a single object, without any timezone information. It is
the most commonly used class when you need to store both date and
time but do not need to account for timezones (e.g., a log entry
timestamp stored in a database alongside timezone metadata, or a
UI display value).
import java.time.*;
import java.time.format.DateTimeFormatter;
public class LocalDateTimeDemo {
public static void main(String[] args) {
// Create LocalDateTime instances
LocalDateTime now = LocalDateTime.now();
LocalDateTime specific = LocalDateTime.of(2026, 7, 23, 14, 30, 0);
LocalDateTime fromParts = LocalDateTime.of(
LocalDate.of(2026, 1, 1),
LocalTime.of(9, 0)
);
System.out.println("Now: " + now);
System.out.println("Specific: " + specific);
System.out.println("FromParts: " + fromParts);
// Arithmetic
LocalDateTime meeting = specific.plusDays(3).plusHours(2).minusMinutes(15);
System.out.println("Meeting: " + meeting);
// Extract date/time parts
System.out.println("Date part: " + specific.toLocalDate());
System.out.println("Time part: " + specific.toLocalTime());
System.out.println("Year: " + specific.getYear());
System.out.println("DayOfWeek: " + specific.getDayOfWeek());
// Formatting
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
String formatted = specific.format(fmt);
System.out.println("Formatted: " + formatted);
// Parsing
LocalDateTime parsed = LocalDateTime.parse("23-07-2026 14:30", fmt);
System.out.println("Parsed: " + parsed);
// isBefore / isAfter
System.out.println("specific isBefore meeting? " + specific.isBefore(meeting));
}
}
Specific: 2026-07-23T14:30
FromParts: 2026-01-01T09:00
Meeting: 2026-07-26T16:15
Date part: 2026-07-23
Time part: 14:30
Year: 2026
DayOfWeek: THURSDAY
Formatted: 23-07-2026 14:30
Parsed: 2026-07-23T14:30
specific isBefore meeting? true
6. ZonedDateTime
ZonedDateTime is a
LocalDateTime with full timezone
information. Use it when scheduling across timezones, displaying
times to users in different regions, or converting between
timezones. Timezones are identified by
ZoneId strings like
"America/New_York" or
"Asia/Kolkata".
import java.time.*;
import java.time.format.DateTimeFormatter;
public class ZonedDateTimeDemo {
public static void main(String[] args) {
// Current time in different timezones
ZonedDateTime utc = ZonedDateTime.now(ZoneId.of("UTC"));
ZonedDateTime newYork = ZonedDateTime.now(ZoneId.of("America/New_York"));
ZonedDateTime london = ZonedDateTime.now(ZoneId.of("Europe/London"));
ZonedDateTime kolkata = ZonedDateTime.now(ZoneId.of("Asia/Kolkata"));
ZonedDateTime tokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println("UTC: " + utc);
System.out.println("New York: " + newYork);
System.out.println("London: " + london);
System.out.println("Kolkata: " + kolkata);
System.out.println("Tokyo: " + tokyo);
// Create a specific ZonedDateTime
ZonedDateTime meeting = ZonedDateTime.of(
LocalDateTime.of(2026, 7, 23, 9, 0),
ZoneId.of("America/New_York")
);
System.out.println("\nMeeting (NY): " + meeting);
// Convert to another timezone
ZonedDateTime meetingLondon = meeting.withZoneSameInstant(ZoneId.of("Europe/London"));
ZonedDateTime meetingKolkata = meeting.withZoneSameInstant(ZoneId.of("Asia/Kolkata"));
System.out.println("Meeting (London): " + meetingLondon);
System.out.println("Meeting (Kolkata): " + meetingKolkata);
// List all available zone IDs (first 5)
System.out.println("\nSample Zone IDs:");
ZoneId.getAvailableZoneIds().stream()
.sorted()
.limit(5)
.forEach(z -> System.out.println(" " + z));
// Formatting ZonedDateTime
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm z");
System.out.println("\nFormatted: " + meeting.format(fmt));
}
}
New York: 2026-07-23T10:30:22.847-04:00[America/New_York]
London: 2026-07-23T15:30:22.847+01:00[Europe/London]
Kolkata: 2026-07-23T20:00:22.847+05:30[Asia/Kolkata]
Tokyo: 2026-07-23T23:30:22.847+09:00[Asia/Tokyo]
Meeting (NY): 2026-07-23T09:00-04:00[America/New_York]
Meeting (London): 2026-07-23T14:00+01:00[Europe/London]
Meeting (Kolkata): 2026-07-23T18:30+05:30[Asia/Kolkata]
Sample Zone IDs:
Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa
Africa/Algiers
Africa/Asmara
Formatted: 23 Jul 2026 09:00 EDT
7. Instant
Instant represents a single point on
the timeline — a machine timestamp measured as the number of
seconds (and nanoseconds) since the Unix epoch (January 1, 1970,
00:00:00 UTC). It has no concept of timezone, date, or
time-of-day. Use it for measuring elapsed time, storing event
timestamps in databases, and interoperating with systems that use
epoch times.
import java.time.*;
public class InstantDemo {
public static void main(String[] args) {
// Current moment
Instant now = Instant.now();
System.out.println("Now (ISO): " + now);
System.out.println("Epoch seconds: " + now.getEpochSecond());
System.out.println("Epoch millis: " + now.toEpochMilli());
System.out.println("Nano adjustment: " + now.getNano());
// Create from epoch value
Instant fromEpoch = Instant.ofEpochSecond(0); // Unix epoch
Instant fromMillis = Instant.ofEpochMilli(1_000_000_000_000L); // 2001
System.out.println("Unix epoch: " + fromEpoch);
System.out.println("From millis: " + fromMillis);
// Arithmetic
Instant future = now.plusSeconds(3600); // 1 hour later
Instant past = now.minusSeconds(86400); // 1 day ago
System.out.println("1 hour later: " + future);
System.out.println("1 day ago: " + past);
// Comparison
System.out.println("past isBefore now? " + past.isBefore(now));
System.out.println("future isAfter now? " + future.isAfter(now));
// Convert Instant to ZonedDateTime (for display)
ZonedDateTime zdt = now.atZone(ZoneId.of("America/New_York"));
System.out.println("Instant as ZDT: " + zdt);
// Measure elapsed time
Instant start = Instant.now();
long sum = 0;
for (int i = 0; i < 1_000_000; i++) sum += i;
Instant end = Instant.now();
long elapsedMs = end.toEpochMilli() - start.toEpochMilli();
System.out.println("Sum: " + sum + ", elapsed: " + elapsedMs + "ms");
}
}
Epoch seconds: 1753281022
Epoch millis: 1753281022847
Nano adjustment: 847000000
Unix epoch: 1970-01-01T00:00:00Z
From millis: 2001-09-08T21:46:40Z
1 hour later: 2026-07-23T15:30:22.847Z
1 day ago: 2026-07-22T14:30:22.847Z
past isBefore now? true
future isAfter now? true
Instant as ZDT: 2026-07-23T10:30:22.847-04:00[America/New_York]
Sum: 499999500000, elapsed: 3ms
8. Duration
Duration represents a time-based
amount — a quantity of time measured in hours, minutes, seconds,
and nanoseconds. It is best suited for measuring differences
between Instant or
LocalTime values (precise time spans).
import java.time.*;
public class DurationDemo {
public static void main(String[] args) {
// Create Duration instances
Duration twoHours = Duration.ofHours(2);
Duration thirtyMinutes = Duration.ofMinutes(30);
Duration ninetySeconds = Duration.ofSeconds(90);
Duration mixed = Duration.ofHours(1).plusMinutes(30).plusSeconds(45);
System.out.println("2 hours: " + twoHours); // PT2H
System.out.println("30 minutes: " + thirtyMinutes); // PT30M
System.out.println("90 seconds: " + ninetySeconds); // PT1M30S
System.out.println("1h 30m 45s: " + mixed); // PT1H30M45S
// Duration between two Instants
Instant start = Instant.parse("2026-07-23T08:00:00Z");
Instant end = Instant.parse("2026-07-23T10:45:30Z");
Duration between = Duration.between(start, end);
System.out.println("Between instants: " + between); // PT2H45M30S
System.out.println(" toHours: " + between.toHours());
System.out.println(" toMinutes: " + between.toMinutes());
System.out.println(" toSeconds: " + between.toSeconds());
System.out.println(" toMillis: " + between.toMillis());
// Duration between two LocalTimes
LocalTime open = LocalTime.of(9, 0);
LocalTime close = LocalTime.of(17, 30);
Duration workDay = Duration.between(open, close);
System.out.println("Work day: " + workDay); // PT8H30M
System.out.printf("Work day: %d hours %d minutes%n",
workDay.toHoursPart(), workDay.toMinutesPart());
// Arithmetic
Duration doubled = twoHours.multipliedBy(2);
Duration halved = twoHours.dividedBy(2);
System.out.println("Doubled: " + doubled);
System.out.println("Halved: " + halved);
// Negative duration
Duration negative = Duration.between(end, start);
System.out.println("Negative: " + negative); // PT-2H-45M-30S
System.out.println("isNegative? " + negative.isNegative());
System.out.println("abs: " + negative.abs());
}
}
30 minutes: PT30M
90 seconds: PT1M30S
1h 30m 45s: PT1H30M45S
Between instants: PT2H45M30S
toHours: 2
toMinutes: 165
toSeconds: 9930
toMillis: 9930000
Work day: PT8H30M
Work day: 8 hours 30 minutes
Doubled: PT4H
Halved: PT1H
Negative: PT-2H-45M-30S
isNegative? true
abs: PT2H45M30S
9. Period
Period represents a date-based amount
in years, months, and days. It operates on calendar dates — unlike
Duration which operates on exact time.
Use Period for human-meaningful date
spans like age calculation, subscription length, or contract
durations.
import java.time.*;
public class PeriodDemo {
public static void main(String[] args) {
// Create Period instances
Period oneYear = Period.ofYears(1);
Period sixMonths = Period.ofMonths(6);
Period tenDays = Period.ofDays(10);
Period oneYearFive = Period.of(1, 5, 10); // 1 year, 5 months, 10 days
System.out.println("1 year: " + oneYear); // P1Y
System.out.println("6 months: " + sixMonths); // P6M
System.out.println("10 days: " + tenDays); // P10D
System.out.println("1Y 5M 10D: " + oneYearFive); // P1Y5M10D
// Period between two LocalDates
LocalDate birth = LocalDate.of(2000, 3, 15);
LocalDate today = LocalDate.of(2026, 7, 23);
Period age = Period.between(birth, today);
System.out.println("Age period: " + age);
System.out.printf("Age: %d years, %d months, %d days%n",
age.getYears(), age.getMonths(), age.getDays());
// Add Period to a date
LocalDate start = LocalDate.of(2026, 1, 1);
LocalDate afterYear = start.plus(Period.ofYears(1));
LocalDate afterSix = start.plus(Period.ofMonths(6));
System.out.println("After 1 year: " + afterYear);
System.out.println("After 6 months: " + afterSix);
// Period arithmetic
Period doubled = Period.of(age.getYears() * 2,
age.getMonths() * 2,
age.getDays() * 2);
System.out.println("Doubled period: " + doubled);
// isNegative
Period neg = Period.between(today, birth);
System.out.println("Negative: " + neg.isNegative());
// Practical: check if 18+ years old
LocalDate dob = LocalDate.of(2010, 5, 20);
Period sinceB = Period.between(dob, today);
boolean isAdult = sinceB.getYears() >= 18;
System.out.println("Born " + dob + " — adult? " + isAdult);
}
}
6 months: P6M
10 days: P10D
1Y 5M 10D: P1Y5M10D
Age period: P26Y4M8D
Age: 26 years, 4 months, 8 days
After 1 year: 2027-01-01
After 6 months: 2026-07-01
Doubled period: P52Y8M16D
Negative: true
Born 2010-05-20 — adult? false
Duration vs Period: Use
Duration for machine-level, exact
time spans (seconds, nanoseconds). Use
Period for human calendar spans
(years, months, days). Do not mix them — a month is not a fixed
number of seconds.
10. DateTimeFormatter
DateTimeFormatter is the thread-safe
replacement for SimpleDateFormat. It
can format date/time objects to strings and parse strings into
date/time objects. It offers predefined formatters and custom
pattern-based formatters.
import java.time.*;
import java.time.format.*;
import java.util.Locale;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
LocalDateTime ldt = LocalDateTime.of(2026, 7, 23, 14, 30, 45);
LocalDate ld = ldt.toLocalDate();
ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/New_York"));
// --- Predefined Formatters ---
System.out.println("ISO_DATE: " +
ld.format(DateTimeFormatter.ISO_DATE));
System.out.println("ISO_DATE_TIME: " +
ldt.format(DateTimeFormatter.ISO_DATE_TIME));
System.out.println("ISO_ZONED_DATE_TIME: " +
zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
System.out.println("RFC_1123_DATE_TIME: " +
zdt.format(DateTimeFormatter.RFC_1123_DATE_TIME));
System.out.println("ISO_LOCAL_DATE: " +
ld.format(DateTimeFormatter.ISO_LOCAL_DATE));
// --- Custom Patterns ---
DateTimeFormatter fmt1 = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
DateTimeFormatter fmt2 = DateTimeFormatter.ofPattern("MMMM dd, yyyy");
DateTimeFormatter fmt3 = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss");
DateTimeFormatter fmt4 = DateTimeFormatter.ofPattern("yyyy/MM/dd h:mm a");
DateTimeFormatter fmt5 = DateTimeFormatter.ofPattern("dd MMM yyyy", Locale.FRENCH);
System.out.println("\nCustom dd-MM-yyyy HH:mm: " + ldt.format(fmt1));
System.out.println("Custom MMMM dd, yyyy: " + ld.format(fmt2));
System.out.println("Custom EEE, dd MMM HH:mm: " + ldt.format(fmt3));
System.out.println("Custom yyyy/MM/dd h:mm a: " + ldt.format(fmt4));
System.out.println("Custom French locale: " + ld.format(fmt5));
// --- Parsing strings to date/time objects ---
System.out.println("\n--- Parsing ---");
String s1 = "23-07-2026 14:30";
LocalDateTime parsed1 = LocalDateTime.parse(s1, fmt1);
System.out.println("Parsed LocalDateTime: " + parsed1);
String s2 = "2026-07-23";
LocalDate parsed2 = LocalDate.parse(s2); // ISO-8601 default
System.out.println("Parsed LocalDate: " + parsed2);
String s3 = "July 23, 2026";
DateTimeFormatter fmtParse = DateTimeFormatter.ofPattern("MMMM dd, yyyy");
LocalDate parsed3 = LocalDate.parse(s3, fmtParse);
System.out.println("Parsed 'July 23, 2026': " + parsed3);
// --- Format pattern reference ---
System.out.println("\n--- Pattern Reference ---");
DateTimeFormatter[] patterns = {
DateTimeFormatter.ofPattern("yyyy"),
DateTimeFormatter.ofPattern("MM"),
DateTimeFormatter.ofPattern("MMMM"),
DateTimeFormatter.ofPattern("dd"),
DateTimeFormatter.ofPattern("EEE"),
DateTimeFormatter.ofPattern("EEEE"),
DateTimeFormatter.ofPattern("HH"),
DateTimeFormatter.ofPattern("mm"),
DateTimeFormatter.ofPattern("ss"),
DateTimeFormatter.ofPattern("SSS")
};
String[] meanings = {
"yyyy = year (4-digit)",
"MM = month (2-digit)",
"MMMM = month (full name)",
"dd = day (2-digit)",
"EEE = weekday (abbrev)",
"EEEE = weekday (full)",
"HH = hour 24h",
"mm = minute",
"ss = second",
"SSS = milliseconds"
};
for (int i = 0; i < patterns.length; i++) {
System.out.println(meanings[i] + " -> " + ldt.format(patterns[i]));
}
}
}
ISO_DATE_TIME: 2026-07-23T14:30:45
ISO_ZONED_DATE_TIME: 2026-07-23T14:30:45-04:00[America/New_York]
RFC_1123_DATE_TIME: Thu, 23 Jul 2026 14:30:45 -0400
ISO_LOCAL_DATE: 2026-07-23
Custom dd-MM-yyyy HH:mm: 23-07-2026 14:30
Custom MMMM dd, yyyy: July 23, 2026
Custom EEE, dd MMM HH:mm: Thu, 23 Jul 14:30:45
Custom yyyy/MM/dd h:mm a: 2026/07/23 2:30 PM
Custom French locale: 23 juil. 2026
--- Parsing ---
Parsed LocalDateTime: 2026-07-23T14:30
Parsed LocalDate: 2026-07-23
Parsed 'July 23, 2026': 2026-07-23
--- Pattern Reference ---
yyyy = year (4-digit) -> 2026
MM = month (2-digit) -> 07
MMMM = month (full name) -> July
dd = day (2-digit) -> 23
EEE = weekday (abbrev) -> Thu
EEEE = weekday (full) -> Thursday
HH = hour 24h -> 14
mm = minute -> 30
ss = second -> 45
SSS = milliseconds -> 000
11. Comparison: Old vs New API
Here is a comprehensive side-by-side comparison of the old and new APIs:
| Concept | Old API (java.util) | New API (java.time) |
|---|---|---|
| Current date | new Date() |
LocalDate.now() |
| Current date and time |
new Date() or
Calendar.getInstance()
|
LocalDateTime.now() |
| Specific date |
new Date(year-1900, month-1, day)
|
LocalDate.of(year, month, day)
|
| Date with timezone |
Calendar.getInstance(TimeZone.getTimeZone("..."))
|
ZonedDateTime.now(ZoneId.of("..."))
|
| Machine timestamp |
System.currentTimeMillis()
|
Instant.now() |
| Add days |
cal.add(Calendar.DAY_OF_MONTH, n)
|
date.plusDays(n) |
| Subtract months |
cal.add(Calendar.MONTH, -n)
|
date.minusMonths(n) |
| Days between dates | Manual subtraction of milliseconds |
ChronoUnit.DAYS.between(d1, d2)
|
| Date-based span | No equivalent | Period.between(d1, d2) |
| Time-based span | Millisecond arithmetic |
Duration.between(t1, t2)
|
| Format date |
new SimpleDateFormat("...").format(date)
|
DateTimeFormatter.ofPattern("...").format(ldt)
|
| Parse string to date |
new SimpleDateFormat("...").parse(str)
|
LocalDate.parse(str, formatter)
|
| Thread safety | Not thread-safe (SimpleDateFormat) | Fully thread-safe (immutable) |
| Mutability | Mutable (setTime, set, etc.) | Immutable (returns new objects) |
| Month indexing | 0-indexed (Jan = 0) | 1-indexed (Jan = 1) — intuitive |
