Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


5.5.1a Fecha y hora en la Librería Estándar C++

§1 Sinopsis

Las utilidades de la LE que tiene relación con el tiempo (fecha y hora) están definidas en el fichero de cabecera <ctime> (antiguo <time.h>) que contiene las funciones que se relacionan en la tabla adjunta.

Nota:  En las descripciones que siguen timestamp es un valor numérico que indica una fecha y hora expresada en segundos después del inicio de la época UNIX (1 de Enero de 1970 00:00:00 GMT). 

Función  Uso
asctime()   Obtener una cadena alfanumérica del tipo Mon Nov 21 11:31:54 1993\n\0 a partir de una estructura tm .
clock()   Obtener el tiempo transcurrido desde el comienzo de la ejecución del programa
ctime()   Obtener una cadena alfanumérica del tipo señalado para asctime a partir de un timestamp.
difftime()   Obtener el tiempo en segundos entre dos timestamp.
gmtime()   Obtener una fecha GMT en formato tm a partir de un timestamp con la hora local.
localtime()   Obtener una fecha en formato tm a partir de un timestamp.
mktime()   Obtener un timestamp numérico a partir de una fecha tm.
strftime()   Obtener una representación alfanumérica a partir de una fecha tm  (acepta un formateo similar a printf)
time()   Obtener un timestamp con la fecha y hora del Sistema.

Además de las funciones anteriores, la STL define tres tipos simples: size_t; clock_ttime_t y una estructura tm. En realidad se trata de typedefs dependientes de la implementación. Por ejemplo, en el fichero <time.h> del compilador Borland C++ encontramos:

typedef long time_t;
size_t El tipo size_t es utilizado en muchas ocasiones. Por ejemplo, es el resultado devuelto por el operador sizeof ( 4.9.13).  Es un entero sin signo cuyo tipo exacto depende de la implementación, aunque suele ser de al menos 32 bits (4 Bytes). Normalmente está definido en diversos ficheros de cabecera, entre otros <ctime>, aunque es frecuente que de una cabecera se redireccione a otra donde realmente está definido. En el caso de MS Visual C++ 6.0 y Borland C++ size_t es un tipo unsigned int ( 2.2.4).
clock_t Representa el valor devuelto por la función clock(). En Borland C++ es un long int ( 2.2.4).
time_t Representa valores devueltos por las funciones time() y mktime(). En MS Visual C++ y Borland C++ es un long int ( 2.2.4).

tm

Es una estructura utilizada por diversas funciones de la Librería para almacenar información relativa a fecha y hora. Por ejemplo: asctime() y localtime().  Responde a la definición siguiente:

struct tm {

 int tm_sec;   // Segundos pasados del minuto (0-61)

 int tm_min;   // Minutos pasados de la hora (0-59)

 int tm_hour;  // Horas desde medianoche (0-23)

 int tm_mday;  // Dia del mes (1-31)

 int tm_mon;   // Número del mes (0-11)

 int tm_year;  // Años transcurridos desde 1900

 int tm_wday;  // Dia de semana (0-6; Domingo = 0)

 int tm_yday;  // Dia del año (0-365)

 int tm_isdst; /* Adelanto de hora para horario de verano

                   1=Si; 0=No; -1=Indefinido */

};

§2 asctime()

La función se presenta en dos versiones: asctime para caracteres normales y _wasctime para caracteres anchos, que responden a los siguientes prototipos:

#include <time.h>
char* asctime(const struct tm* tmPtr);
wchar_t* _wasctime(const struct tm* tmPtr);

Descripción:

Ambas funciones aceptan un puntero a una estructura tipo tm , y devuelven un puntero a una cadena de caracteres con información alfanumérica sobre la fecha contenida en la estructura. La cadena es de ancho fijo (26 caracteres), mantiene siempre el mismo formato, y es reescrita cada vez que se invoca la función:

Mon Nov 21 11:31:54 1993\n\0

El reloj utilizado es de 24 horas, y cualquiera que sea el tipo de caracteres utilizados (anchos o estrechos), termina en los caracteres NL (New Line) y NUL (nulo).

Ejemplo:

#include <iostream>
using namespace std;

#include <ctime>

int main() {    // ==================
  struct tm myt;
  myt.tm_sec = 1;   myt.tm_min = 30; myt.tm_hour = 9;
  myt.tm_mday = 22; myt.tm_mon = 11; myt.tm_year = 56;
  myt.tm_wday = 4;  myt.tm_yday = 0; myt.tm_isdst = 0;

  char* cTim = asctime(&myt));
  cout << "Fecha resultante: " << cTim;
  return 0;
}

Salida:

Fecha resultante: Thu Dec 22 09:30:01 1956

§3 clock()

Prototipo:

#include <time.h>
clock_t clock(void);

Descripción:

Esta función devuelve un valor de tipo clock_t que representa el tiempo desde el comienzo del programa hasta el momento de invocación de la función. Mediante invocaciones sucesivas puede ser utilizada para obtener el tiempo entre dos puntos del programa.  En caso de error, si el tiempo de proceso no está disponible o no es representable, la función devuelve -1.

El valor devuelto representa el número de "tics" del RTC desde el inicio del programa. Es posible calcular este valor en segundos dividiéndolo por una constante denominada CLK_TCK en unos sistemas y CLOCKS_PER_SEC en otros. Definida en <ctime>.

En el fichero <time.h> del compilador Borland C++ 5.5 encontramos las definiciones siguientes:

#define CLOCKS_PER_SEC 1000.0
#define CLK_TCK 1000.0

Ejemplo:

cout << "Desde el inicio: " << clock()/CLK_TCK << " segundos\n";

Otro ejemplo ( 9.1).

§4 ctime()

Esta función se presenta en dos versiones: ctime para caracteres normales y _wctime para caracteres anchos. Prototipos:

#include <ctime>
char* ctime(const time_t* sTptr);
wchar_t* _wctime(const time_t* sTptr);

Descripción:

Ambas funciones aceptan un puntero a un valor time_t que supuestamente contiene un timestamp expresado en segundos después del inicio de la época UNIX (1 de Enero de 1970 00:00:00 GMT). Por ejemplo un valor devuelto por la función time().  Ambas funciones devuelven un puntero a una cadena de 26 caracteres que contiene la fecha y hora con un formato alfanumérico en el que todos los campos tienen siempre el mismo ancho, y que es reescrita cada vez que se invoca a la función (el reloj utilizado es de 24 horas):

Mon Nov 21 11:31:54 1993\n\0

Si la fecha corresponde a un momento anterior a Enero de 1970 se obtiene una cadena nula.

Ejemplo:

#include <iostream>
using namespace std;
#include <ctime>

int main() { // =================
   time_t tSec = 31536000;
   time_t* tPtr = &tSec;
   char* sTptr = ctime(tPtr);
   cout << "Fecha: " << sTptr ;
   return 0;
}

Salida:

Fecha: Fri Jan 01 01:00:00 1971

§5 difftime()

Prototipo:

#include <time.h>
double difftime(time_t time2, time_t time1);

Descripción:

La función acepta dos valores tipo time_t y devuelve un double con el tiempo entre ambos valores expresado en segundos.

Ejemplo:

#include <iostream>

using namespace std;

#include <ctime>

int main() {       // =================
   time_t first, second;
   first = time(NULL);
   delay(2000);     // esperar 2 segundos
   second = time(NULL);
   cout << "Diferencia: " << difftime(second, first)) << " segundos\n";
   return 0;
}

§6 gmtime()

Prototipo:

#include <time.h>
struct tm* gmtime(const time_t* tPtr);

Descripción:

La función acepta un puntero a un tipo time_t, que suponemos contiene una fecha local (por ejemplo, obtenida con la función time ), y devuelve un puntero a una estructura tipo tm que contiene la fecha convertida a la hora GMT correspondiente.

Esta función puede ser útil en un programa que maneje comunicaciones por Internet, donde es costumbre utilizar la hora GMT en vez de la hora local.

Ejemplo:

#include <iostream>
using namespace std;
#include <ctime>

int main() {                  // =================
   time_t tSac = time(NULL);  // instante actual


   struct tm* pt1 = localtime(&tSac);
   cout << "hh:mm:ss " << pt1->tm_hour << ":" << pt1->tm_min << ":"
                       << pt1->tm_sec << endl;
   cout << "dd-mm-aaaa: " << pt1->tm_mday << "-" << pt1->tm_mon+1 << "-"
                          << pt1->tm_year+1900 << endl;

   tm tm2 = *gmtime(&tSac);   // deferencia y asignación
   cout << "hh:mm:ss " << tm2.tm_hour << ":" << tm2.tm_min << ":"
                       << tm2.tm_sec << endl;
   cout << "dd-mm-aaaa: " << tm2.tm_mday << "-" << tm2.tm_mon+1 << "-"
        << tm2.tm_year+1900 << endl;
   return 0;

}

Salida:

hh:mm:ss 22:45:2
dd-mm-aaaa: 23-5-2003
hh:mm:ss 5:45:2
dd-mm-aaaa: 24-5-2003

Comentario:

Suponemos que el ordenador está situado en S. Francisco (USA), donde utilizan el horario PDT. En Mayo ya rige el horario de verano que tiene un retraso de 7 horas respecto a la hora Zulú. Cuando en S. Francisco son las 22:45 del día 23, en Greenwich son las 5:45 de la madrugada del día 24.

§7 localtime()

Esta función, junto con time(), es posiblemente una de las más útiles de entre las que se refieren a asuntos de fecha y hora.

Prototipo:

#include <time.h>
struct tm* localtime(const time_t* timer);

Descripción:

La función acepta un puntero a un tipo time_t, que contiene una fecha expresada en segundos desde el inicio de la época UNIX, y devuelve un puntero a una estructura tm cuyos miembros contienen información sobre la fecha introducida. Sus miembros son sobreescritos con cada invocación a la función.

Ejemplo:

#include <iostream>
using namespace std;
#include <ctime>

int main() {            // =================
   char* dS[7] = {"Domingo","Lunes","Martes","Miercoles",

                  "Jueves","Viernes","Sabado"};
   time_t tSac = time(NULL);       // instante actual
   struct tm* tmP = localtime(&tSac);

   cout << "hh:mm:ss " << tmP->tm_hour << ":" << tmP->tm_min << ":"
                       << tmP->tm_sec << endl;
   cout << "dd-mm-aaaa: " << tmP->tm_mday << "-" << tmP->tm_mon+1 << "-"
                          << tmP->tm_year+1900 << endl;
   cout << "Dia de semana: " << dS[tmP->tm_wday] << endl;
   cout << "Dia del año: " << tmP->tm_yday << endl;
   cout << "Horario de verano: " << (tmP->tm_isdst ? "Si" : "No") << endl;
   return 0;
}

Salida:

hh:mm:ss 11:13:23
dd-mm-aaaa: 22-5-2003
Dia de semana: Jueves
Dia del año: 141
Horario de verano: Si

§8 mktime()

Prototipo:

#include <time.h>
time_t mktime(struct tm* tmPtr);

Descripción:

La función mktime realiza justamente la operación inversa que la anterir localtime().  Acepta un puntero a una estructura tm con información sobre una fecha y devuelve un valor tipo time_t con el tiempo en segundos desde el inicio de la época UNIX.

§9 strftime()

Esta función se presenta en dos versiones: strftime para caracteres normales y wcsftime para caracteres anchos.

Prototipo:

#include <time.h>
size_t strftime(char* str, size_t maxsize,

                const char* fmt, const struct tm* mPt);
size_t wcsftime(wchar_t* str, size_t maxsize,

                const wchar_t* fmt, const struct tm* mPt);

Descripción:

Como puede verse, la función devuelve un tipo size_t, y acepta cuatro argumentos: un puntero-a-carácter str que señala una cadena de caracteres donde se obtendrá el resultado; un tipo size_t maxize; un puntero a cadena de caracteres constante fmt y un puntero mPt a una estructura tm que suponemos contiene datos de una fecha.

La función produce una cadena alfanumérica terminada en un carácter nulo, y la sitúa en el lugar señalado por str. El valor devuelto es la longitud de esta cadena incluyendo el carácter de terminación. En caso de error, o si la longitud resulta mayor que maxsize, el valor devuelto es cero y el resultado obtenido (cadena situada en str) es indeterminado.

La cadena producida es una versión de la fecha contenida en la estructura, pero formateada según determinados códigos de formateo que se sitúan en la cadena señalada por fmt.  El sistema es similar al de la conocida función printf() que proporciona salidas formateadas. Los códigos permitidos son muy numerosos, de forma que puede controlarse todos los detalles de la representación (consulte el manual de su compilador al respecto).

Ejemplo:

#include <iostream>
using namespace std;
#include <ctime>

int main() {                 // =================
   time_t tSac = time(NULL); // instante actual
   tm tms = *localtime(&tSac);

   cout << "hh:mm:ss " << tms.tm_hour << ":" << tms.tm_min << ":"
                       << tms.tm_sec << endl;
   cout << "dd-mm-aaaa: " << tms.tm_mday << "-" << tms.tm_mon+1 << "-"
                          << tms.tm_year+1900 << endl;

   char sRes[80];
   size_t r = strftime(sRes, 80,
           "Son %M minutos pasados de las %I horas (%Z) %A, %B %d 20%y",
           &tms);
   if (r) cout << sRes;
   return 0;
}

Salida:

hh:mm:ss 20:14:13
dd-mm-aaaa: 24-5-2003
Son 14 minutos pasados de las 08 horas (WET) Saturday, May 24 2003

§10 time()

Esta función devuelve la hora actual del sistema en segundos desde el inicio de la época UNIX (1 de Enero de 1970 00:00:00 GMT).

Prototipo:

#include <ctime>
time_t time(time_t* tPtr);

Descripción:

La función acepta un puntero a time_t y devuelve un valor time_t que es el tiempo en segundos transcurrido desde el inicio de la época UNIX. En realidad puede realizar dos funciones: si se pasa un valor no nulo, el valor correspondiente se almacena en el sitio señalado por el puntero. Si este valor es nulo entonces el valor no se almacena en ningún sitio. En cualquier caso siempre devuelve un valor con el instante actual en segundos desde las 0 horas del 1 de Enero de 1970.

Nota:  Como es costumbre, si se produce un error la función devuelve -1. Esto puede ocurrir si el sistema no tiene reloj de tiempo real, lo que no es normal en sistemas que soporten compiladores C++. Sí podía ocurrir en algunos sistemas dedicados antiguos, basados en microprocesadores que disponían de compiladores C.

Ejemplo:

#include <iostream>
using namespace std;
#include <ctime>

int main() {  // =================
   time_t t1 = 0;
   time_t* pt1 = &t1;
   time(pt1);
   cout << "Desde la epoca UNIX " << *pt1 << " segundos\n";


   time_t t2 = time(NULL);
   cout << "Desde la epoca UNIX " << t2 << " segundos\n";
   return 0;
}

Salida:

Desde la epoca UNIX 1053550492 segundos
Desde la epoca UNIX 1053550492 segundos

Nota:  Puesto que en Borland C++ el tipo time_t es un long int cuyo rango superior es 2,147,483,647 y un año comprende aproximadamente 31,536,000 segundos, el límite superior se alcanzará algo más de 68 años después de Enero de 1970 (el 18 de Enero del año 2038). Por esta razón muchos fabricantes están empezando a utilizar tipos de 64 bits para este typedef.

§11 Bibliografía & Otras librerías

Una buena introducción al asunto del tiempo y la hora en los ordenadores y en cómo se ha implementado en las aplicaciones C/C++ lo tiene en el siguiente documento -especialmente en la introducción-. A Foundation to Sleep On (Clocks, Points in Time, and Time Durations).

Las funciones de la Librería Estándar suelen ser suficientes para la mayoría de aplicaciones prácticas, y presentan la ventaja de su portabilidad. Sin embargo, los compiladores suelen incluir otras, que por lo general no son portables. Por ejemplo, Borland ofrece una serie de funciones auxiliares que solo son utilizables para Windows-32. Para aplicaciones específicas pueden encontrarse librerías comerciales e incluso gratuitas, algunas de las cuales se indican en la página que hemos dedicado a las librerías C/C++ www.zator.com.

Mi consejo particular es que antes de tomar una decisión al respecto, eche un vistazo a las siguientes librerías pertenecientes a la colección Boost [1].

  • Date_Time de Jeff Garland.
  • Ratio. de Howard Hinnant, Beman Dawes y Vicente J. Botet Escriba.
  • Chrono de Howard Hinnant, Beman Dawes y Vicente J. Botet Escriba.

 

  Inicio.


[1]  Estas librerías tienen Copyright, pero como el resto de la citada colección, las condiciones de la licencia de uso son muy generosas:

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following:

The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor.