Java provides multiple APIs for handling date and time, evolving significantly over versions to address design flaws and usability issues.
Legacy java.util.Date
The java.util.Date class represents a specific instant in time with millisecond precision. Despite its name, it encapsulates both date and time.
Date now = new Date(); // Current timestamp
// Deprecated constructor: year is offset from 1900, month is 0-based
Date legacyDate = new Date(95, 11, 17); // December 17, 1995
Accessing components uses deprecated methods:
int year = now.getYear() + 1900; // Add 1900 to get actual year
int month = now.getMonth() + 1; // Add 1 to convert from 0-based index
int day = now.getDate(); // Day of month (1–31)
int hour = now.getHours(); // Hour in 24-hour format
Similarly, mutation methods like setYear() and setMonth() are deprecated due to poor design and lack of time zone awareness.
Comparison is supported via:
boolean earlier = now.before(legacyDate);
boolean later = now.after(legacyDate);
boolean same = now.equals(legacyDate);
java.util.Calendar
Calendar is an abstract class offering more flexible date manipulation than Date. It’s typically instantiated via getInstance():
Calendar cal = Calendar.getInstance(); // Uses default time zone and locale
Field access uses constants:
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1; // Still 0-based
int day = cal.get(Calendar.DAY_OF_MONTH);
Setting values:
cal.set(1995, Calendar.DECEMBER, 17); // Month constant avoids off-by-one errors
Arithmetic operations:
cal.add(Calendar.DAY_OF_MONTH, 1); // Add one day
cal.add(Calendar.YEAR, -1); // Subtract one year
Note: Calendar is mutable and not thread-safe. Each thread should use its own instance.
Modern java.time API (Java 8+)
The java.time package inrtoduces immutable, thread-safe, and intuitive classes:
LocalDate dateOnly = LocalDate.now();
LocalTime timeOnly = LocalTime.now();
LocalDateTime full = LocalDateTime.now();
Formatting uses DateTimeFormatter:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String output = full.format(fmt);
Parsing is equally straightforward:
LocalDateTime parsed = LocalDateTime.parse("2024-08-05T15:30:00");
// Or with custom format
LocalDateTime customParsed = LocalDateTime.parse("2024-08-05 15:30:00", fmt);
This API avoids the pitfalls of earlier classes by separating date-only, time-only, and combined representations, and by being inherently immutable.
SimpleDateFormat (Legacy Formatting)
Part of java.text, SimpleDateFormat handles parsing and formatting for Date objects:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatted = sdf.format(new Date());
try {
Date parsed = sdf.parse("2024-08-05 15:30:00");
} catch (ParseException e) {
e.printStackTrace();
}
Common pattern symbols include:
yyyy– four-digit yearMM– two-digit monthdd– two-digit dayHH– hour (24-hour)mm– minutesss– seconds
However, SimpleDateFormat is not thread-safe and should not be shared across threads without synchronization.
Given its limitations, the java.time API is strongly preferred for new code.