variable time_t tiempo sirve que para hora funcion fecha example c++ c

c++ - tiempo - time_t time time_t*)



Forma fácil de convertir una estructura tm(expresada en UTC) a un tipo time_t (8)

¿Cómo hago lo anterior? Hay función mktime pero trata la entrada como expresada en tiempo local, pero ¿cómo realizo la conversión si mi variable de entrada tm está en UTC?


Use timegm () en lugar de mktime ()


timegm() funciona, pero no está presente en todos los sistemas.

Aquí hay una versión que solo usa ANSI C. (EDITAR: no estrictamente ANSI C! Estoy haciendo matemáticas en time_t, suponiendo que las unidades están en segundos desde la época. AFAIK, el estándar no define las unidades de time_t.) Nota , utiliza un truco, por así decirlo, para determinar el huso horario de la máquina y luego ajusta el resultado de mktime en consecuencia.

/* returns the utc timezone offset (e.g. -8 hours for PST) */ int get_utc_offset() { time_t zero = 24*60*60L; struct tm * timeptr; int gmtime_hours; /* get the local time for Jan 2, 1900 00:00 UTC */ timeptr = localtime( &zero ); gmtime_hours = timeptr->tm_hour; /* if the local time is the "day before" the UTC, subtract 24 hours from the hours to get the UTC offset */ if( timeptr->tm_mday < 2 ) gmtime_hours -= 24; return gmtime_hours; } /* the utc analogue of mktime, (much like timegm on some systems) */ time_t tm_to_time_t_utc( struct tm * timeptr ) { /* gets the epoch time relative to the local time zone, and then adds the appropriate number of seconds to make it UTC */ return mktime( timeptr ) + get_utc_offset() * 3600; }


La siguiente implementación de timegm(1) funciona timegm(1) en Android, y probablemente también funciona en otras variantes de Unix:

time_t timegm( struct tm *tm ) { time_t t = mktime( tm ); return t + localtime( &t )->tm_gmtoff; }


Este es realmente un comentario con código para abordar la respuesta de Leo Accend: Pruebe lo siguiente:

#include <time.h> #include <stdio.h> #include <stdlib.h> /* * A bit of a hack that lets you pull DST from your Linux box */ time_t timegm( struct tm *tm ) { // From Leo''s post, above time_t t = mktime( tm ); return t + localtime( &t )->tm_gmtoff; } main() { struct timespec tspec = {0}; struct tm tm_struct = {0}; if (gettimeofday(&tspec, NULL) == 0) // clock_gettime() is better but not always avail { tzset(); // Not guaranteed to be called during gmtime_r; acquire timezone info if (gmtime_r(&(tspec.tv_sec), &tm_struct) == &tm_struct) { printf("time represented by original utc time_t: %s/n", asctime(&tm_struct)); // Go backwards from the tm_struct to a time, to pull DST offset. time_t newtime = timegm (&tm_struct); if (newtime != tspec.tv_sec) // DST offset detected { printf("time represented by new time_t: %s/n", asctime(&tm_struct)); double diff = difftime(newtime, tspec.tv_sec); printf("DST offset is %g (%f hours)/n", diff, diff / 3600); time_t intdiff = (time_t) diff; printf("This amounts to %s/n", asctime(gmtime(&intdiff))); } } } exit(0); }



Aquí hay una solución que uso (No recuerdo dónde la encontré) cuando no es una plataforma de Windows

time_t _mkgmtime(const struct tm *tm) { // Month-to-day offset for non-leap-years. static const int month_day[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; // Most of the calculation is easy; leap years are the main difficulty. int month = tm->tm_mon % 12; int year = tm->tm_year + tm->tm_mon / 12; if (month < 0) { // Negative values % 12 are still negative. month += 12; --year; } // This is the number of Februaries since 1900. const int year_for_leap = (month > 1) ? year + 1 : year; time_t rt = tm->tm_sec // Seconds + 60 * (tm->tm_min // Minute = 60 seconds + 60 * (tm->tm_hour // Hour = 60 minutes + 24 * (month_day[month] + tm->tm_mday - 1 // Day = 24 hours + 365 * (year - 70) // Year = 365 days + (year_for_leap - 69) / 4 // Every 4 years is leap... - (year_for_leap - 1) / 100 // Except centuries... + (year_for_leap + 299) / 400))); // Except 400s. return rt < 0 ? -1 : rt; }


Página POSIX para tzset , describe la variable global extern long timezone longzonezone que contiene la zona horaria local como un desplazamiento de segundos desde UTC. Esto estará presente en todos los sistemas compatibles con POSIX.

Para que la zona horaria contenga el valor correcto, es probable que necesite llamar a tzset() durante la inicialización de su programa.

A continuación, puede agregar timezone a la salida de mktime para obtener la salida en UTC.

#include <stdio.h> #include <stdlib.h> #include <time.h> time_t utc_mktime(struct tm *t) { return mktime(t) + timezone; } int main(int argc, char **argv) { struct tm t = { 0 }; tzset(); utc_mktime(&t); }

Nota: Técnicamente, tzset() y mktime() no garantizan que sean seguros para la rosca .

Si un hilo accede a tzname, [XSI] [Option Start] daylight, o timezone [Option End] directamente mientras hay otro hilo en una llamada a tzset (), o a cualquier función que se requiera o permita establecer información de zona horaria como si llamando a tzset (), el comportamiento no está definido.

... pero la mayoría de las implementaciones sí lo están. GNU C usa mutexes en tzset() para evitar modificaciones concurrentes a las variables globales que establece, y mktime() ve un uso muy amplio en programas con subprocesos sin sincronización. Sospecho que si uno encontrara efectos secundarios, sería usando setenv() para alterar el valor de TZ como se hace en la respuesta de @liberforce.


La respuesta de Loki Astari fue un buen comienzo, el timegm es una de las posibles soluciones. Sin embargo, la página man de timegm proporciona una versión portátil, ya que timegm no es compatible con POSIX. Aquí está:

#include <time.h> #include <stdlib.h> time_t my_timegm(struct tm *tm) { time_t ret; char *tz; tz = getenv("TZ"); if (tz) tz = strdup(tz); setenv("TZ", "", 1); tzset(); ret = mktime(tm); if (tz) { setenv("TZ", tz, 1); free(tz); } else unsetenv("TZ"); tzset(); return ret; }