New CTO Bans java.util.Date Usage—Why Ignoring It Can Get You Fired

The article explains the fundamental design flaws of java.util.Date—misleading name, mutability, non‑finality, timezone quirks, and legacy numbering—why a CTO may forbid its use, and provides a step‑by‑step guide to replace it with java.time classes such as Instant, LocalDateTime and ZonedDateTime.

Java Tech Enthusiast
Java Tech Enthusiast
Java Tech Enthusiast
New CTO Bans java.util.Date Usage—Why Ignoring It Can Get You Fired

1. Problems with java.util.Date

java.util.Date is a poorly designed type; most of its members were deprecated in Java 1.1.

Misleading name : it represents an instant, similar to java.time.Instant.

Non‑final : inheritance is allowed (e.g., java.sql.Date), which adds confusion.

Mutable : methods such as setTime mutate the value, forcing developers to create defensive copies.

Implicit system timezone : toString() uses the local timezone, producing unexpected results.

Zero‑based month and 1900‑based year : legacy C‑style numbering leads to off‑by‑one errors.

Unclear method names : getDate() returns day of month, getDay() returns day of week.

Leap‑second handling is vague : getSeconds() actually returns 0‑59.

Over‑tolerant ranges : dates such as “January 32” are accepted and rolled over.

Date class key reasons
Date class key reasons

2. Why the change is required

A static‑analysis rule marks any usage of java.util.Date (or java.sql.Date) as a defect that blocks release, so the code base must be refactored.

Defect scan rule
Defect scan rule

3. Migration steps

3.1 Map database columns to java.time types

If the column stores date + time → use LocalDateTime.

If it stores only a date → use LocalDate.

If it stores only a time → use LocalTime.

If it stores a timestamp with zone → use Instant or ZonedDateTime.

3.2 Update data‑object (DO) classes

Replace Date fields with the selected java.time type.

3.3 Refactor DateUtil methods

Replace constructions such as new Date() and Calendar.getInstance().getTime() with the new API.

Date nowDate = new Date();
Date nowCalendarDate = Calendar.getInstance().getTime();

After migration:

// Instant represents a point in time, similar to Date
Instant nowInstant = Instant.now();

// Full date‑time without zone
LocalDateTime nowLocalDateTime = LocalDateTime.now();

// With explicit zone handling
ZonedDateTime nowZonedDateTime = ZonedDateTime.now();

// Convert back to java.util.Date when legacy APIs still require it
Date nowFromDateInstant = Date.from(nowInstant);
java.sql.Timestamp nowFromInstant = java.sql.Timestamp.from(nowInstant);

Basic method conversions

dateFormat

public static String dateFormat(Date date, String dateFormat) {
    SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
    return formatter.format(date);
}

After migration:

public static String dateFormat(LocalDateTime date, String dateFormat) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
    return date.format(formatter);
}

addSecond / addMinute / addHour / addDay / addMonth / addYear

Old implementation uses Calendar. New implementation uses the fluent plusXxx methods of LocalDateTime:

public static LocalDateTime addSecond(LocalDateTime date, int second) {
    return date.plusSeconds(second);
}
public static LocalDateTime addMinute(LocalDateTime date, int minute) {
    return date.plusMinutes(minute);
}
public static LocalDateTime addHour(LocalDateTime date, int hour) {
    return date.plusHours(hour);
}
public static LocalDateTime addDay(LocalDateTime date, int day) {
    return date.plusDays(day);
}
public static LocalDateTime addMonth(LocalDateTime date, int month) {
    return date.plusMonths(month);
}
public static LocalDateTime addYear(LocalDateTime date, int year) {
    return date.plusYears(year);
}

dateToWeek

public static String dateToWeek(LocalDate date) {
    DayOfWeek dayOfWeek = date.getDayOfWeek();
    return WEEK_DAY_OF_CHINESE[dayOfWeek.getValue() % 7];
}

getStartTimeOfDay / getEndTimeOfDay

public static LocalDateTime getStartTimeOfDay(LocalDateTime date) {
    if (date == null) return null;
    return date.toLocalDate().atStartOfDay();
}
public static LocalDateTime getEndTimeOfDay(LocalDateTime date) {
    if (date == null) return null;
    return date.toLocalDate().atTime(LocalTime.MAX);
}

betweenStartAndEnd

public static Boolean betweenStartAndEnd(Instant nowTime, Instant beginTime, Instant endTime) {
    return nowTime.isAfter(beginTime) && nowTime.isBefore(endTime);
}

Notes

Instant

is timezone‑independent and corresponds to the old Date semantics. LocalDateTime lacks zone information; converting to a timestamp requires combining it with a ZoneId (e.g., via ZonedDateTime). ZonedDateTime includes zone data and behaves similarly to Calendar.

When interacting with legacy APIs that still expect java.util.Date, use Date.from(Instant) to bridge the gap.

4. Summary

Replacing java.util.Date propagates through data objects, converters, and DTOs; a missed replacement causes compilation errors or runtime failures, making the migration high‑cost but unavoidable.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backendJavamigrationrefactoringdate-timejava.timejava.util.Date
Java Tech Enthusiast
Written by

Java Tech Enthusiast

Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.