Why a Simple Date‑Difference Function Broke My Game Server and How to Fix It
A game server bug caused hundreds of reward emails to be sent on New Year's Day because a copied Java date‑difference function returned incorrect values for cross‑year dates, and the issue was resolved by replacing it with a reliable Java 8 time API implementation.
The author, a game server developer, needed to award offline players based on the number of days they were away. The logic required calculating the day difference between the last offline time and the current login time.
Instead of writing the calculation, the author copied a Java function from the web that used Calendar to compute the difference. The function worked for months but failed when the two dates spanned different years and the first date was later than the second.
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; // leap year
} else {
timeDistance += 365; // common year
}
}
return timeDistance + (day2 - day1);
} else {
System.out.println("判断day2 - day1 : " + (day2 - day1));
return day2 - day1;
}
}On 2020‑01‑01 the function returned 358 days for the call differentDays("2020-1-1", "2019-12-25"), where the correct result should be –7. This caused the system to send hundreds of reward emails, breaking game balance.
To fix the bug, the author rewrote the method using Java 8's java.time API, which handles leap years and cross‑year calculations correctly.
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 Generic.long2int(localDate1.until(localDate2, ChronoUnit.DAYS));
}
public static LocalDate date2LocalDate(Date date) {
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
LocalDate localDate = instant.atZone(zoneId).toLocalDate();
return localDate;
}After deploying the corrected code, the erroneous reward distribution stopped. The author also recovered the mistakenly sent items, apologized to players, and emphasized the importance of testing any third‑party code before using it in production.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
