Legacy Date API
Why you still need to know the old classes
Modern date and time code is usually built on java.time,
but older projects and some APIs still use
java.util.Date, Calendar,
and SimpleDateFormat.
It is important to be able to read and convert them even if new code should not be built around them.
Date
Despite its name, Date in modern use effectively
represents an instant with millisecond precision relative to the epoch.
The class still contains many deprecated methods for manipulating date components,
so it should not be treated as a convenient calendar model.
Date legacy = new Date();
Instant instant = legacy.toInstant();
The conversion back is just as direct:
Date legacy = Date.from(instant);
This bridge allows you to keep the old type only at the API boundary
and use Instant and other java.time classes inside the application.
Calendar
Calendar appeared as a more capable calendar model,
but it has mutable state, a complicated API, and historically awkward details.
For example, months in some old calls are numbered from zero.
Calendar calendar = Calendar.getInstance();
calendar.set(2026, Calendar.SEPTEMBER, 18);
In new code, similar tasks are usually expressed more clearly with
LocalDate, LocalDateTime,
or ZonedDateTime, depending on the meaning of the value.
SimpleDateFormat
The legacy API often used SimpleDateFormat for formatting.
An important problem with it is mutability and the lack of thread safety.
The modern DateTimeFormatter is immutable and thread-safe,
so it is usually a safer choice.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
String text = LocalDate.of(2026, 9, 18).format(formatter);
How to work with legacy APIs in a project
A practical approach is to convert the old type as close to the integration boundary as possible.
For example, if a library returns Date,
convert it to Instant immediately and use the modern model afterward.
The same idea works in reverse if an older API requires a Date.
java.time class.