1927: The moment time went backwards
\n\nImagine: you are writing a simple Java script to calculate the difference between two dates in milliseconds. You take 1927, subtract one value from another — and instead of 3600 seconds (one hour), you get a strange number. You double-check the code, Google it, and find the legendary StackOverflow question with thousands of views. And you realize: you are not alone.
\n\nThis bug is a true artifact of history that still frightens beginners. In this article, we will break down why subtracting epoch-milli times in 1927 gives a strange result, show it with real Java code examples, and, most importantly, give you working ways to avoid this trap. If you work with historical data or just want to write reliable code — this information is for you.
\n\nThe essence of the problem: The magic of December 31, 1927
\n\nLet's get straight to the code. Here is a classic example that breaks your brain:
\n\nimport java.util.TimeZone;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class StrangeDateDifference {\n public static void main(String[] args) throws Exception {\n TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");\n SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\n sdf.setTimeZone(tz);\n\n Date date1 = sdf.parse("1927-12-31 23:54:07");\n Date date2 = sdf.parse("1927-12-31 23:54:08");\n\n long diff = date2.getTime() - date1.getTime();\n System.out.println("Difference in milliseconds: " + diff);\n // Expect 1000, but get...\n }\n}\n\nYou run it — and instead of 1000 milliseconds (1 second), you see 353? Or even a negative number? Congratulations, you have encountered the 1927 date subtraction error.
\n\nThe reason is not a Java bug (though there is one too, but more on that later). The reason is a historical time zone change. On December 31, 1927, in Shanghai (Asia/Shanghai), something strange happened: at 23:54:08, local time was turned back by 5 minutes and 52 seconds. In effect, a second lasted not 1000 ms, but only 353 ms. Java faithfully reflects this historical fact, but to a developer, it looks like magic.
\n\nTop mistakes developers make
\n\n1. Blind trust in old APIs (java.util.Date and SimpleDateFormat)
\n\nThe first and most popular mistake is using the outdated classes java.util.Date and SimpleDateFormat. They are not only inconvenient but also contain hidden surprises, especially when working with historical dates.
How to avoid: Use java.time (Java 8+). For example:
import java.time.LocalDateTime;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.time.format.DateTimeFormatter;\n\npublic class SafeDateDifference {\n public static void main(String[] args) {\n DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");\n ZoneId zone = ZoneId.of("Asia/Shanghai");\n\n LocalDateTime ldt1 = LocalDateTime.parse("1927-12-31 23:54:07", formatter);\n LocalDateTime ldt2 = LocalDateTime.parse("1927-12-31 23:54:08", formatter);\n\n ZonedDateTime zdt1 = ldt1.atZone(zone);\n ZonedDateTime zdt2 = ldt2.atZone(zone);\n\n long diff = zdt2.toInstant().toEpochMilli() - zdt1.toInstant().toEpochMilli();\n System.out.println("Difference in milliseconds: " + diff);\n // You will still get a strange number, but at least you will know why!\n }\n}\n\n2. Ignoring historical time zone changes
\n\nMany people think that time zones are just a fixed offset from UTC. But in reality, they have changed dozens of times over the last 100 years.