1927: El momento en que el tiempo retrocedió
\n\nImagina: escribes un simple script en Java para calcular la diferencia entre dos fechas en milisegundos. Tomas el año 1927, restas un valor del otro y obtienes no 3600 segundos (una hora), sino un número extraño. Revisas el código, buscas en Google y encuentras la legendaria pregunta en StackOverflow con miles de visitas. Y te das cuenta: no estás solo.
\n\nEste bug es un verdadero artefacto histórico que aún asusta a los principiantes. En este artículo analizaremos por qué restar epoch-milli times en 1927 da un resultado extraño, lo mostraremos con ejemplos reales de código Java y, lo más importante, daremos formas prácticas de evitar esta trampa. Si trabajas con datos históricos o simplemente quieres escribir código robusto, esta información es para ti.
\n\nEl núcleo del problema: La magia del 31 de diciembre de 1927
\n\nVayamos directo al código. Aquí tienes un ejemplo clásico que desconcierta:
\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("Diferencia en milisegundos: " + diff);\n // Esperamos 1000, pero obtenemos...\n }\n}\n\nLo ejecutas y, en lugar de 1000 milisegundos (1 segundo), ves 353? ¿O incluso un número negativo? Felicidades, te has topado con el error de resta de fechas de 1927.
\n\nLa causa no es un bug de Java (aunque también lo es, pero hablaremos de eso después). La causa es un cambio histórico en la zona horaria. El 31 de diciembre de 1927 en Shanghái (Asia/Shanghai) ocurrió algo extraño: a las 23:54:08, la hora local se atrasó 5 minutos y 52 segundos. De hecho, el segundo duró no 1000 ms, sino solo 353 ms. Java refleja fielmente este hecho histórico, pero para el desarrollador parece magia.
\n\nTop errores que cometen los desarrolladores
\n\n1. Confianza ciega en APIs antiguas (java.util.Date y SimpleDateFormat)
\n\nEl primer y más popular error es usar las clases obsoletas java.util.Date y SimpleDateFormat. No solo son incómodas, sino que también contienen sorpresas ocultas, especialmente al trabajar con fechas históricas.
Cómo evitarlo: Usa java.time (Java 8+). Por ejemplo:
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("Diferencia en milisegundos: " + diff);\n // Igual obtendrás un número extraño, ¡pero al menos sabrás por qué!\n }\n}\n\n2. Ignorar los cambios históricos de las zonas horarias
\n\nMuchos piensan que las zonas horarias son simplemente un desplazamiento fijo respecto a UTC. Pero en realidad han cambiado docenas de veces en los últimos 100 años.