Look at this Java code:
public class MainTest {
public static void main(String[] args) throws Exception {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse("1900-01-01 08:00:00");
System.out.println(simpleDateFormat.format(date));
}
}
What do you expect the output to be? Most people would say: 1900-01-01 08:00:00
But running this code produces: 1900-01-01 08:05:43
That's a difference of 5 minutes and 43 seconds (343 seconds). While a time difference of 8 hours can be explained by timezone offset, and a difference of 1 hour by daylight saving time, this specific offset with seconds and minutes is puzzling.
The Root Cause
This behavior stems from historical timezone database changes. The OpenJDK bug tracker documents this issue:
The timezone data for Shanghai in 1900 showed an unusual offset:
The timezone offset was UTC +8:05:43 hours all of the period.
This 343-second offset was originally attributed to a timezone change on December 31, 1927 at midnight, where clocks were set back 5 minutes and 52 seconds. However, the timezone database (TZDB) maintained by IANA has been updated multiple times since then, shifting where this offset is applied.
The Evolution of Historical Timezone Data
A famous StackOverflow question illustrates this phenomenon:
This question, asked over a decade ago, has been viewed over 746,000 times. In 2013, the TZDB version 2013a changed the transition time from 23:54:08 to 23:54:03, altering the calculation result from 353 seconds to 358 seconds.
By version 2014f, the transition was moved to 1900-12-31, resulting in only a 343-second change. This explains why modern JDK versions behave differently than older ones for the same input.
Why Java Handles It This Way
Java unified timezone handling by treating all moments before 1900 in the UTC timezone as standard time. Any offset difference are applied at the beginning of the timeline. So when parsing 1900-01-01 08:00:00 in a UTC+8 timezone, Java adds 8 hours to get 1900-01-01 08:00:00 UTC, then applies the pre-calculated 343-second offset accumulated from historical timezone adjustments, resulting in 1900-01-01 08:05:43.
You can verify this behavior yourself:
public static void main(String[] args) throws ParseException {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str3 = "1927-12-31 23:54:07";
String str4 = "1927-12-31 23:54:08";
Date sDt3 = sf.parse(str3);
Date sDt4 = sf.parse(str4);
long ld3 = sDt3.getTime() / 1000;
long ld4 = sDt4.getTime() / 1000;
System.out.println(ld4 - ld3); // Outputs: 1 (not 353)
}
The time difference appears as 1 second on modern JDK versions, yet the underlying timezone calculation has undergone significant shifts.
The Official Position
The earliest related JDK bug dates back to 2005:
The official response stated that this issue would not be fixed to avoid compatibility problems. The behavior is now considered a feature rather than a bug due to deep historical reasons in timezone data management.
This quirk demonstrates how timezone handling in programming languages must balance mathematical correctness with historical accurcay, and how the TZDB updates can fundamentally alter date calculations across different versions.