Skip to content

Why is subtracting these two times (in 1927) giving a strange result?

When subtracting two times in Java and getting a strange result, the most common cause for dates around 1927 is a historical timezone offset change. In several regions (notably Shanghai, China), local mean time was standardized to a fixed UTC offset on December 31, 1927, creating a multi-second gap. If you parse these dates without explicit timezone handling, Java may interpret them as continuous, leading to unexpected subtraction results.

Here is how to correctly handle this using java.time:

java
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.Duration;

public class TimeSubtraction {
    public static void main(String[] args) {
        // Dates around the 1927 Shanghai timezone shift
        LocalDateTime start = LocalDateTime.of(1927, 12, 31, 23, 54, 07);
        LocalDateTime end = LocalDateTime.of(1927, 12, 31, 23, 54, 08);

        // Naive subtraction ignores historical timezone shifts
        Duration naiveDuration = Duration.between(start, end);
        System.out.println("Naive: " + naiveDuration.getSeconds() + " seconds");

        // Explicit timezone handling applies the correct historical offset
        ZonedDateTime zonedStart = start.atZone(ZoneId.of("Asia/Shanghai"));
        ZonedDateTime zonedEnd = end.atZone(ZoneId.of("Asia/Shanghai"));

        Duration correctDuration = Duration.between(zonedStart, zonedEnd);
        System.out.println("With timezone: " + correctDuration.getSeconds() + " seconds");
    }
}
  1. Always use ZonedDateTime or Instant for historical dates. LocalDateTime has no timezone context and will assume a continuous timeline.
  2. Parse strings with explicit timezones using DateTimeFormatter and ZoneId to avoid ambiguous interpretations.
  3. Use Duration.between() for elapsed time calculations instead of manual arithmetic on epoch milliseconds.
  4. The year 1927 is highly relevant here due to global standardization of time zones. Older explanations often incorrectly blame leap years or date arithmetic; modern Java time subtraction should rely on java.time classes, which automatically apply the correct historical timezone database rules.

Dual-run preview — compare with live Symfony routes.