zona ver unidos servidor mexico malasia lumpur los kuala horas horaria hora hay exacta estados españa entre diferencia cuantas cambiar california angeles c linux timezone

unidos - Conversión de zona horaria C API en Linux, ¿alguien?



hora exacta (6)

Estoy buscando algo que presumí que sería muy simple: dada la hora local de Unix en una zona horaria específica (especificada como una cadena, por ejemplo, "America / New_York" - tenga en cuenta que no es mi hora local), obtenga el valor de hora correspondiente en GMT. Es decir, algo en la línea de

time_t get_gmt_time(time_t local_time, const char* time_zone);

Tan engañosamente simple como suena, lo más cercano que pude encontrar fue el siguiente fragmento de código de la página man de timegm:

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

Tiene que haber una mejor manera que esta abominación beligerante, sin hilos, ¿verdad? ¿¿Derecha??


¿Por qué no puedes usar gmtime_r() ? Siguiendo funcionó bien para mí:

int main() { time_t t_gmt, t_local=time(NULL); struct tm tm_gmt; gmtime_r(&t_local, &tm_gmt); t_gmt = mktime(&tm_gmt); printf("Time now is: %s", ctime(&t_local)); printf("Time in GMT is: %s", ctime(&t_gmt)); return 0; }


Desde tzfile (5), que documenta los archivos en / usr / share / zoneinfo (en mi sistema) con un detalle horrible:

Parece que la zona horaria usa tzfile internamente, pero glibc se niega a exponerlo al espacio del usuario. Esto es más probable porque las funciones estandarizadas son más útiles y portátiles, y en realidad están documentadas por glibc.

Nuevamente, esto probablemente no sea lo que está buscando (es decir, una API), pero la información está ahí y puede analizarla sin demasiado dolor.


El problema con gmtime, localtime y sus variantes es la dependencia de la variable de entorno TZ. Las funciones de tiempo primero llaman a tzset (void), que lee TZ para determinar desplazamientos DST, etc. Si TZ no está configurado en el entorno del usuario, (g) libc usa la zona horaria del sistema. Por lo tanto, si tiene una estructura local, por ejemplo, ''Europa / París'' y su máquina o entorno está configurado como ''América / Denver'', se aplicará un desplazamiento incorrecto al convertir a GMT. Todas las funciones de tiempo llaman a tzset (void) que lee TZ para configurar char * tzname [2], zona horaria larga (dif, en segundos, desde GMT) e int daylight (booleano para DST). La configuración de estos directamente no tiene ningún efecto, ya que tzset () los sobrescribirá la próxima vez que llame a la hora local, etc.

Me enfrenté con el mismo problema que ''igor'' en la pregunta original, mientras que setenv funciona, parece problemático (¿volver a entrar?). Decidí buscar más para ver si podía modificar tzset (void) a tzset (char *) para establecer explícitamente las variables mencionadas anteriormente. Bueno, por supuesto, es solo una mala idea ... pero al probar la fuente de glibc y la fuente de la base de datos de la IANA de la IANA, llegué a la conclusión de que el enfoque setenv no es tan malo.

Primero, setenv solo modifica el proceso global ''char ** environ'' (no el shell de llamada, por lo que la TZ ''real'' no se ve afectada). Y, segundo, glibc en realidad pone un bloqueo en setenv. El inconveniente es que las llamadas setenv / tzset no son atómicas, por lo que posiblemente otro hilo podría escribir en TZ antes del tzset original. Pero una aplicación bien implementada que usa hilos debería estar pendiente de eso de todos modos.

Sería bueno si POSIX definiera tzset tomar un char * para buscar en la extensa base de datos de IANA TZ (y que tome el valor NULL para ''usar el usuario o el sistema TZ /), pero si falla eso, setenv parece estar bien.


Quería añadir un poco más de detalle aquí.

Si intentas lo siguiente:

#include <stdio.h> #include <time.h> /* defines ''extern long timezone'' */ int main(int argc, char **argv) { time_t t, lt, gt; struct tm tm; t = time(NULL); lt = mktime(localtime(&t)); gt = mktime(gmtime(&t)); printf( "(t = time(NULL)) == %x,/n" "mktime(localtime(&t)) == %x,/n" "mktime(gmtime(&t)) == %x/n" "difftime(...) == %f/n" "timezone == %d/n", t, lt, gt, difftime(gt, lt), timezone); return 0; }

te darás cuenta de que las conversiones de zona horaria aseguran que:

  • mktime(localtime(t)) == t , y
  • mktime(gmtime(t)) == t + timezone ,
    por lo tanto:
  • difftime(mktime(gmtime(t)), mktime(localtime(t))) == timezone
    (esta última es una variable global iniciada por tzset() o la invocación de cualquier función de conversión de zona horaria).

Ejemplo de salida de lo anterior:

$ TZ=GMT ./xx (t = time(NULL)) == 4dd13bac, mktime(localtime(&t)) == 4dd13bac, mktime(gmtime(&t)) == 4dd13bac difftime(...) == 0.000000 timezone == 0 $ TZ=EST ./xx (t = time(NULL)) == 4dd13baf, mktime(localtime(&t)) == 4dd13baf, mktime(gmtime(&t)) == 4dd181ff difftime(...) == 18000.000000 timezone == 18000 $ TZ=CET ./xx (t = time(NULL)) == 4dd13bb2, mktime(localtime(&t)) == 4dd13bb2, mktime(gmtime(&t)) == 4dd12da2 difftime(...) == -3600.000000 timezone == -3600

En ese sentido, está intentando "hacerlo al revés": time_t se trata como absoluto en UN * X, es decir, siempre en relación con el "EPOCH" (0:00 UTC del 01/01/1970).

La diferencia entre UTC y la zona horaria actual (última llamada tzset() ) está siempre en la external long timezone global.

Eso no elimina la fealdad de la manipulación del entorno, pero puede ahorrarse el esfuerzo de pasar por mktime() .


Realmente pensé que había algo en glib, pero parece que lo recordé mal. Sé que probablemente estés buscando un código C directo, pero aquí tienes lo mejor que tengo:

Sé que Python tiene cierta noción de zonas horarias a través de una clase tzinfo ; puede leer sobre ello en la documentación de datetime . Puede ver el código fuente del módulo (en el tarball , está en Módulos / datetime.c) - parece tener algo de documentación, por lo que tal vez pueda sacar algo del mismo.


Similar a la respuesta de Python, puedo mostrarte lo que hace R :

R> now <- Sys.time() # get current time R> format(now) # format under local TZ [1] "2009-08-03 18:55:57" R> format(now,tz="Europe/London") # format under explicit TZ [1] "2009-08-04 00:55:57" R> format(now,tz="America/Chicago") # format under explicit TZ [1] "2009-08-03 18:55:57" R>

pero R usa una representación interna que extiende la struct tm habitual struct tm --- vea R-2.9.1 / src / main / datetime.c.

Aún así, este es un tema delicado y sería bueno si fuera la biblioteca estándar. Tal vez no sea su mejor apuesta es usar Boost Date_Time (ejemplo)