estoy usando el estándar mktime
función para convertir un struct tm
en un valor de tiempo de época. los tm
los campos se completan localmente y necesito obtener la hora de la época como GMT. tm
tiene un gmtoff
campo para permitirle establecer el desplazamiento GMT local en segundos solo para este propósito.
Pero no puedo entender cómo obtener Esa información. ¿Seguramente debe haber una función estándar en algún lugar que devuelva el desplazamiento? Cómo localtime
¿hazlo?

alca
Solo haz lo siguiente:
#define _GNU_SOURCE /* for tm_gmtoff and tm_zone */
#include <stdio.h>
#include <time.h>
/* Checking errors returned by system calls was omitted for the sake of readability. */
int main(void)
{
time_t t = time(NULL);
struct tm lt = {0};
localtime_r(&t, <);
printf("Offset to GMT is %lds.\n", lt.tm_gmtoff);
printf("The time zone is '%s'.\n", lt.tm_zone);
return 0;
}
Nota: Los segundos desde la época devueltos por time()
se miden como en Greenwich.

iabdalkader
¿Cómo lo hace localtime?
De acuerdo a localtime
página man
La función localtime() actúa como si llamara a tzset(3) y establece las variables externas tzname con información sobre la zona horaria actual,
zona horaria con la diferencia entre la hora universal coordinada (UTC) y la hora estándar local en segundos
Así que podrías llamar localtime()
y tendrás la diferencia en timezone
o llamar tzset()
:
extern long timezone;
....
tzset();
printf("%ld\n", timezone);
Nota: si elige ir con localtime_r()
tenga en cuenta que no es necesario establecer esas variables que deberá llamar tzset()
primero en establecer timezone
:
De acuerdo con POSIX.1-2004, se requiere que localtime() se comporte como si se llamara a tzset(), mientras que localtime_r() no tiene este requisito. Para el código portátil, tzset() debe llamarse antes que localtime_r()
Supongo que debería haber buscado un poco más antes de preguntar. Resulta que hay un poco conocido timegm
función que hace lo contrario de gmtime
. Es compatible con GNU y BSD, lo cual es lo suficientemente bueno para mis propósitos. Una solución más portátil es establecer temporalmente el valor de la TZ
variable de entorno a “UTC” y luego usar mktime
luego establezca TZ
espalda.
Pero timegm
funciona para mi.

colina
La versión universal de obtener la función de compensación de hora local está aquí.
Tomé prestados fragmentos de código de esta respuesta en stackoverflow.
int time_offset()
{
time_t gmt, rawtime = time(NULL);
struct tm *ptm;
#if !defined(WIN32)
struct tm gbuf;
ptm = gmtime_r(&rawtime, &gbuf);
#else
ptm = gmtime(&rawtime);
#endif
// Request that mktime() looksup dst in timezone database
ptm->tm_isdst = -1;
gmt = mktime(ptm);
return (int)difftime(rawtime, gmt);
}

Mariusz Jaskółka
Esta es la solución portátil que debería funcionar en todas las plataformas C (y C++) estándar:
const std::time_t epoch_plus_11h = 60 * 60 * 11;
const int local_time = localtime(&epoch_plus_11h)->tm_hour;
const int gm_time = gmtime(&epoch_plus_11h)->tm_hour;
const int tz_diff = local_time - gm_time;
Agregar std::
espacio de nombres cuando se usa C++. El resultado está en horas en el rango [-11, 12];
Explicación:
Simplemente convertimos la fecha y hora “1970-01-01 11:00:00” a tm
estructura dos veces: con la zona horaria local y con el GMT. El resultado es la diferencia entre las horas parciales.
Se ha elegido “11:00::00” porque este es el único punto de tiempo (considerando GMT) cuando tenemos la misma fecha en todo el mundo. Por ese hecho, no tenemos que considerar la magia adicional con el cambio de fecha en los cálculos.
ADVERTENCIA
La versión anterior de mi respuesta funcionó solo en Linux:
// DO NOT DO THAT!!
int timezonez_diff = localtime(&epoch_plus_11h)->tm_hour -
gmtime(&epoch_plus_11h)->tm_hour;
Es posible que esto no funcione porque el almacenamiento para el resultado tm
objeto devuelto como un puntero de localtime
y gmtime
se puede compartir (y está en windows/msvc). Ahí es donde he introducido temporales para el cálculo.
Creo que lo siguiente es cierto al menos en Linux: la información de la zona horaria proviene de /usr/share/zoneinfo/. localtime lee /etc/localtime que debería ser una copia del archivo apropiado de zoneinfo. Puedes ver lo que hay dentro haciendo zdump -v
en el archivo de zona horaria (zdump puede estar en sbin pero no necesita permisos elevados para leer archivos de zona horaria con él). Aquí hay un recorte de uno:
/usr/share/zoneinfo/EST5EDT Sun Nov 6 05:59:59 2033 UTC = Sun Nov 6 01:59:59 2033 EDT isdst=1 gmtoff=-14400
/usr/share/zoneinfo/EST5EDT Sun Nov 6 06:00:00 2033 UTC = Sun Nov 6 01:00:00 2033 EST isdst=0 gmtoff=-18000
/usr/share/zoneinfo/EST5EDT Sun Mar 12 06:59:59 2034 UTC = Sun Mar 12 01:59:59 2034 EST isdst=0 gmtoff=-18000
/usr/share/zoneinfo/EST5EDT Sun Mar 12 07:00:00 2034 UTC = Sun Mar 12 03:00:00 2034 EDT isdst=1 gmtoff=-14400
/usr/share/zoneinfo/EST5EDT Sun Nov 5 05:59:59 2034 UTC = Sun Nov 5 01:59:59 2034 EDT
Supongo que podrías analizar esto tú mismo si quieres. No estoy seguro de si hay una función stdlib que simplemente devuelve el gmtoff (puede que la haya, pero no sé…)
editar: man tzfile describe el formato del archivo zoneinfo. Debería poder simplemente mapear en una estructura del tipo apropiado. Parece ser lo que está haciendo zdump basado en un rastro de él.

Duke Nukem
Aquí hay una frase de dos líneas inspirada en las respuestas de @Hill y @friedo:
#include <time.h>
...
time_t rawtime = time(0);
timeofs = timegm(localtime(&rawtime)) - rawtime;
Devuelve el desplazamiento de UTC en segundos.
no necesita _GNU_SOURCE
definido, pero tenga en cuenta que timegm
no es un estándar POSIX y es posible que no esté disponible fuera de GNU y BSD.
“
tm
tiene ungmtoff
field” –> que es una extensión de biblioteca C no estándar.– chux – Reincorporar a Monica
1 de febrero de 2018 a las 21:36