Portada arrow Algoritmos arrow Sumar y restar fechas: día juliano
Sumar y restar fechas: día juliano
sábado, 07 de octubre de 2006

El calendario Gregoriano, el que utilizamos en el mundo occidental, es un tanto complicado cuando queremos operar con sus fechas. Está lleno de irregularidades. Cuando queremos operar con fechas necesitamos un método que nos simplifique un poco la vida.

Por ejemplo, plantéate lo siguiente: ¿Qué fecha será dentro de 37 días?...

Cuesta calcularlo, ¿verdad? Yo acabaría contando con los dedos.

Pues imagínate esto: ¿Qué fecha fue hace 1386 días? Hacen falta demasiados dedos.

Afortunadamente, hay una forma sencilla de hacerlo, y salvar las irregularidades del calendario Gregoriano: utilizar el calendario juliano de los astrónomos.

Los astrónomos necesitan una medida del tiempo extremadamente precisa, universal y sencilla de utilizar. Ellos utilizan un calendario un tanto "especial", al que denominan calendario juliano astronómico. Básicamente, asignan a cada día un número entero.

Por ejemplo, imagínate que el 30 de diciembre de 1987 tuviera asignado el número 2447160. Pues el día siguiente será el 2447161, y el siguiente el 2447162... y así sucesivamente

[...]
30/Dic/1987 -> 2447160
31/Dic/1987 -> 2447161
01/Ene/1988 -> 2447162
02/Ene/1988 -> 2447163
03/Ene/1988 -> 2447164
etc...

Los astrónomos consideran que el día empieza a mediodia (en el meridiano de Greenwich) y termina al mediodía siguiente. Entre un mediodía y otro, utilizan decimales para representar la hora, minutos, segundos, etc..

Si nosotros contabilizasemos así, los cálculos que se proponen al principio serían mucho más fáciles ¿Verdad?

Pues bien, utilicemos una versión simplificada del calendario de los astrónomos. Olvidándonos de las horas y minutos.

Si pudiesemos contar con una función que dada una fecha Gregoriana le asignase un número natural, con la condición de que a fechas consecutivas le correspondan números naturales consecutivos, y otra que, al revés, dado un número natural que representa un día nos dijera la fecha Gregoriana que le corresponde, podríamos sumar y restar fechas fácilmente.

Realmente, incluso no es necesario utilizar la misma numeración que los astrónomos (que puede resultar un poco complicada). Basta con que el sistema de numeración respete numerar las fechas correlativamente, y que escojamos como fecha número "1", una suficientemente atrás en el tiempo como para que nos permita hacer nuestros cálculos.

Pues bien, esas funciones existen. Se basan en que el año solar (el tiempo que tarda la tierra en dar la vuelta al sol) es de 365,256363 días

 

Para compensar los 0,256363 días que "sobran" de cada año civil, el calendario gregoriano utiliza una serie de ajustes, como los años bisiestos (1 día extra cada cuatro años) y otras correcciones más.

Las funciones que se presentan a continuación tienen en cuenta estas peculiaridades del calendario gregoriano, y para una fecha gregoriana dada, obtienen el correspondiente día juliano y viceversa.

Además, en el cálculo del día juliano astronómico hay involucrados una cierta cantidad de valores reales (con decimales), lo cual forzaría a trabajar con aritmética de coma flotante. No obstante, como no queremos tanta precisión como los astrónomos, sino simplemente asignar un entero a cada fecha, podemos simplificar las fórmulas para trabajar con aritmética entera, mucho menos costosa computacionalmente hablando.

Estos dos métodos en C# hacen exactamente eso, y son fácilmente traducibles a cualquier otro lenguaje.

 
long gregorianoajuliano(int dia, int mes, int anno) {
   //dada una fecha del calendario gregoriano, obtiene
   //un entero que la representa
   long tmes, tanno;
   long jdia;
   //marzo es el mes 0 del año
   if (mes > 2)
   {
      tmes = mes - 3;
      tanno = anno;
   }
   else
   //febrero es el mes 11 del año anterior.
   {
      tmes = mes + 9;
      tanno = anno - 1;
   }
   jdia = (tanno / 4000) * 1460969;
   tanno = (tanno % 4000);
   jdia = jdia +
      (((tanno / 100) * 146097) / 4) +
      (((tanno % 100) * 1461) / 4) +
      (((153 * tmes) + 2) / 5) +
      dia +
      1721119;
   return jdia;    
}
 
 
datetime julianoagregoriano(long jdia)
   {
   long anno, mes, dia;
   long tmp1, tmp2;
   tmp1 = jdia - 1721119;
   anno = ((tmp1 - 1) / 1460969) * 4000;
   tmp1 = ((tmp1 - 1) % 1460969) + 1;
   tmp1 = (4 * tmp1) - 1;
   tmp2 = (4 * ((tmp1 % 146097) / 4)) + 3;
   anno = (100 * (tmp1 / 146097)) + (tmp2 / 1461) + anno;
   tmp1 = (5 * (((tmp2 % 1461) + 4) / 4)) - 3;
   mes = tmp1 / 153;
   dia = ((tmp1 % 153) + 5) / 5;
   if (mes < 10)
      mes = mes + 3;
   else
   {
      mes = mes - 9;
      anno = anno + 1;
   }
   return new datetime((int)anno, (int)mes, (int)dia);
}
 

De esta manera, si hoy es 7 del 10 de 2006, saber qué día fue hace 1386 días (como planteábamos al principio se podria expresar como:

 
julianoagregoriano(
   gregorianoajuliano(7,10,1986)-
   1386
   )
 

Análogamente, para saber cuántos días faltan para navidad (25/12/2006) desde el 7 del 10 de 2006:

 
 
 
gregorianoajuliano(25,12,2006) -
gregorianoajuliano(7,10,1986)
 

También podemos darnos cuenta de que mediante el resto de la división de un día juliano por el 7 podemos obtener el día de la semana. No obstante, si eso es lo único que necesitamos, es más adecuada la Congruencia de Zeller, que implica unos cálculos más sencillos).

 
←Artículo anterior   Artículo siguiente→

Categorías

Suscríbete

RSS feed Sindicación RSS

(¿Qué es la sindicación RSS?)


Suscribir por e-mail

¿Dónde estoy?

Estás en La tecla de ESCAPE, un sitio web personal en el que nos gusta hablar de algoritmos, informática, tecnología, ciencia, ingeniería, internet... y cualquier tontería que se nos ocurra. El punto de vista de nuestros artículos técnicos suele ser muy básico, así que a menudo adoptamos grandes simplificaciones. (Más...-Términos de uso)