From - Wed Nov 13 18:02:54 1996 Path: news.unizar.es!news.rediris.es!minerva.ibernet.es!news.ctv.es!usenet From: Juan Conejero Gil Newsgroups: es.comp.lenguajes.c Subject: Re: time.h Date: Tue, 12 Nov 1996 23:51:31 +0100 Organization: AVA/SKYCAD Lines: 154 Message-ID: <3288FF73.493@ctv.es> References: <3288E796.5E0D@arrakis.es> NNTP-Posting-Host: ctv4095.ctv.es Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit X-Mailer: Mozilla 2.01Gold (Win95; I) Felipe Núñez wrote: > Estoy haciendo una clase que te permite leer y modificar la fecha y > hora. Quiero que compile en DOS, UNIX y MAC, y a la hora de leer la hora > no hay problema: uso time para obtener los segundos desde el Epoch, y > luego localtime para convertirlo en la fecha y hora. > Pero para cambiar la hora solo conozco stime que admite como argumento > un time_t que represente los segundos desde el Epoch. Lo que no se es > cómo pasar la fecha y hora que quiero introducir a segundos desde el > maldito 1970. > Me han sugerido que haga los cálculos, pero no se por donde empezar. > ¿Podría darme alguien alguna solución? > Muchas gracias. > > judas@arrakis.es mktime() de la biblioteca estándar, tal como te ha sugerido J.A. Gutiérrez, es una solución transportable. Sin embargo, creo que una solución más general al problema que planteas, y de paso a cualquier problema relacionado con fechas e intervalos de tiempo, puede ser de gran interés. El tratamiento riguroso del tiempo requiere el manejo de algoritmos relacionados con números de día juliano. El número de día juliano (JD) correspondiente a un instante dado se define como el número de días transcurridos desde el 1.5 de enero de -4712 en cualquier escala de tiempo. JD se emplea principalmente en astronomía para la expresión del tiempo, ya que al ser una numeración lineal, independiente de meses y años, simplifica de forma esencial la medida de intervalos de tiempo así como todos los algoritmos en los que el tiempo es la variable independiente. Los algoritmos relacionados con el número de día juliano que implementamos aquí son debidos a Jean Meeus (1) y son válidos para todo JD >= 0, es decir, para cualquier instante igual o posterior a -4712 enero 1.5. Estos algoritmos tienen además en cuenta la Reforma Gregoriana del calendario, de manera que el día siguiente al 4 de octubre de 1582 es el 15 de octubre de 1582, o principio del calendario gregoriano. Las fechas son manipuladas por estos algoritmos en el sistema astronómico de enumeración de fechas. Según este sistema, la fecha anterior al 1 de enero del año 1 es el 31 de diciembre del año 0, y la fecha anterior al 1 de enero del año 0 es el 31 de diciembre del año -1. Este sistema es diferente del empleado muchas veces por los historiadores, que consideran el año -1 como inmediatamente anterior al año 1, ignorando el año 0, con la consiguiente incorrección aritmética. En las funciones que se definen a continuación el parámetro 'DD' es el día de una fecha con decimales; por ejemplo, para una fecha cualquiera a las 14h57m39s, DD = día_de_la_fecha + 14/24 + 57/1440 + 39/86400. MM es el número del mes de la fecha, desde 1=enero hasta 12=diciembre. (1) Meeus, Jean. Astronomical Algorithms. Willmann-Bell, 1991. pp 59-63. /* -*- begin code -*- */ /* * Cálculo del JD para la fecha dada por YY, MM, DD (año, mes, día). */ double DateToJD( int YY, int MM, double DD ) { int Y = YY, M = MM; double JD; if ( MM <= 2 ) { Y--; M += 12; } JD = (long)(365.25*(Y+4716)) + (long)(30.6001*(M+1)) + DD - 1524.5; if ( YY > 1582 || YY == 1582 && (MM > 10 || MM == 10 && DD >= 15) ) { long A = Y/100; return JD + (2 - A + (A >> 2)); } return JD; } /* * Cálculo de los elementos YY, MM, DD (año, mes, día) de la fecha * correspondiente a un JD. La función asegura que los elementos MM y DD son coherentes, * es decir, tiene en cuenta el número de días para cada mes, años bisiestos, etc. */ void JDToDate( double JD, int *YY, int *MM, double *DD ) { long Z, A, B, D; int C, E; JD += 0.5; A = Z = JD; if ( Z >= 2299161L ) { long a = (Z-1867216.25) / 36524.25; A += 1 + a - (a >> 2); } B = A+1524; C = (B-122.1) / 365.25; D = 365.25*C; E = (B-D) / 30.6001; *DD = B - D - (long)(30.6001*E) + (JD-Z); *MM = E - ((E < 14) ? 1 : 13); *YY = C - ((*MM > 2) ? 4716 : 4715); } /* -*- end code -*- */ Algunas ejemplos sencillos de aplicación de JD: * Cálculo del intervalo Delta en días transcurrido desde una fecha dada por Y1, M1, D1 a otra fecha dada por Y2, M2, D2: Delta = DateToJD( Y2, M2, D2 ) - DateToJD( Y1, M1, D1 ); Para expresar Delta en segundos (pregunta original), basta con hacer Delta*86400L. Naturalmente, Delta < 0 si {Y1,M1,D1} es posterior a {Y2,M2,D2}. * Cálculo de la fecha Y2, M2, D2 que resulta al transcurrir un intervalo Delta en días a partir de una fecha Y1, M1, D1 (problema inverso al anterior): JDToDate( DateToJD( Y1, M1, D1 )+Delta, &Y2, &M2, &D2 ); * Cálculo del día de la semana W correspondiente a una fecha cualquiera Y, M, D: W = (int)((unsigned long)(DateToJD( Y, M, D )+1.5) % 7); 0 <= W < 7, donde 0=domingo, 1=lunes,... 6=sábado * Cálculo del número N del día del año al que corresponde una fecha Y, M, D: N = 1 + (int)(DateToJD( Y, M, D ) - DateToJD( Y, 1, 1 )); El día 1 del año es el 1 de enero. El último día del año es 365 ó 366, para años normales o bisiestos, respectivamente. * Hacer un calendario perpetuo (al menos desde -4712) es trivial mediante JD. Para transformar una fracción de día (parte fraccionaria del argumento DD en las funciones anteriores) en hh (horas), mm (minutos) y ss (segundos): #include /* ... */ double fh = 24 * (DD-(int)DD), fm; double ss = 60 * modf( 60 * modf( fh, &fh ), &fm ); int hh = (int)fh; int mm = (int)fm; -- // ****************************** // Juan Conejero Gil, AVA/SKYCAD // mailto:skycad@ctv.es // http://www.ctv.es/USERS/skycad // ******************************