Bug in Java Date Difference Calculation Caused Massive Reward Emails and Its Fix Using Java 8 API

A game server developer copied a flawed Java function to calculate offline days, which mis‑computed the difference across year boundaries, leading to thousands of erroneous reward emails on 2020‑01‑01, and the issue was resolved by switching to the Java 8 date‑time API.

Architect's Tech Stack
Architect's Tech Stack
Architect's Tech Stack
Bug in Java Date Difference Calculation Caused Massive Reward Emails and Its Fix Using Java 8 API

The author, a game server developer, needed to send item rewards to players based on the number of days they were offline. The implementation was straightforward: compute the day interval between the last offline time and the current login, then award items accordingly. To avoid writing the calculation from scratch, the author copied a Java function from an online source.

public static int differentDays(Date date1, Date date2) {
    Calendar cal1 = Calendar.getInstance();
    cal1.setTime(date1);
    Calendar cal2 = Calendar.getInstance();
    cal2.setTime(date2);
    int day1 = cal1.get(Calendar.DAY_OF_YEAR);
    int day2 = cal2.get(Calendar.DAY_OF_YEAR);
    int year1 = cal1.get(Calendar.YEAR);
    int year2 = cal2.get(Calendar.YEAR);
    if (year1 != year2) {
        int timeDistance = 0;
        for (int i = year1; i < year2; i++) {
            if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) {
                timeDistance += 366;
            } else {
                timeDistance += 365;
            }
        }
        return timeDistance + (day2 - day1);
    } else {
        System.out.println("判断day2 - day1 : " + (day2 - day1));
        return day2 - day1;
    }
}

For several months the function appeared to work, but on 2020‑01‑01 it returned 358 days for the call differentDays("2020-1-1", "2019-12-25") instead of the correct -7. This error caused the system to send hundreds of reward emails, severely breaking the game’s item balance. Investigation revealed that the bug occurs when the two dates are in different years and the first date is later than the second, because the algorithm incorrectly adds whole‑year day counts without handling negative intervals.

The problem was fixed by abandoning the custom calendar logic and using the modern Java 8 date‑time API, which correctly handles all edge cases:

public static int differentDays(Date date1, Date date2) {
    if (date1 == null || date2 == null) {
        throw new RuntimeException("日期不能为空");
    }
    LocalDate localDate1 = date2LocalDate(date1);
    LocalDate localDate2 = date2LocalDate(date2);
    return (int) localDate1.until(localDate2, ChronoUnit.DAYS);
}

public static LocalDate date2LocalDate(Date date) {
    Instant instant = date.toInstant();
    ZoneId zoneId = ZoneId.systemDefault();
    return instant.atZone(zoneId).toLocalDate();
}

The author concludes with a warning: never blindly copy unknown code into production; always test thoroughly, and prefer the robust, well‑designed APIs provided by the language, such as Java 8’s date‑time classes, to avoid hidden bugs that can cause serious operational issues.

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.

Game Developmentdatetimebugjava8
Architect's Tech Stack
Written by

Architect's Tech Stack

Java backend, microservices, distributed systems, containerized programming, and more.

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.