Pregunta

Tengo una función que escribí (si no es un buen sustituto estándar, por favor hágamelo saber ...)

time_t get_unix_time(string time_str) {
    time_t loctime;
    time(&loctime);

    struct tm *given_time;
    time_str = time_str.substr(0, time_str.find_first_of('.'));

    replace(time_str.begin(), time_str.end(), ':', ',');
    replace(time_str.begin(), time_str.end(), '-', ',');
    replace(time_str.begin(), time_str.end(), '/', ',');
    replace(time_str.begin(), time_str.end(), ' ', ',');

    given_time = localtime(&loctime);
    vector<string> trecord = split_string(time_str, ',');

    given_time->tm_year = atoi(trecord.at(0).c_str()) - 1900;
    given_time->tm_mon  = atoi(trecord.at(1).c_str()) - 1;
    given_time->tm_mday = atoi(trecord.at(2).c_str());
    given_time->tm_hour = atoi(trecord.at(3).c_str());
    given_time->tm_min  = atoi(trecord.at(4).c_str());
    given_time->tm_sec  = atoi(trecord.at(5).c_str());

    return mktime(given_time);
}

La entrada (time_str) a la función tiene el formato 1970-01-01 00: 00: 00.0 . La función split_string () divide la time_str cadena en un vector que contiene:

{1970, 01, 01, 00, 00, 00}

que se utiliza para rellenar la estructura de given_time.

Me escribió una función para probarlo, y se la pasó exactamente esa entrada (comienzo de la época). Sin embargo, el tiempo que me devuelve es 21600, que es 1970-01-01 06:00:00 o GMT + 6 . El resultado esperado es 0 (comienzo de la época).

Nota: que yo estoy en la zona horaria entre Estados Unidos y Centroamérica, que es GMT - 6. En la medianoche del 1 Ene 1970 CST, hora UTC @ habría será el 1 Ene 1970 06:00:00

¿Hay algo en mi función que es lo que es específico para mi zona horaria? haciendo algo mal en esta función Am I, o ¿Puedo hacer algo diferente para que sea independiente de Zona, o al menos siempre UTC.

¿Fue útil?

Solución

Si está utilizando glibc que tienen la función timegm a su disposición, que es una versión de mktime que siempre interpreta el tiempo como si fuera en la zona horaria GMT. Por desgracia, la documentación para esa función, básicamente, establece que no puede de otra manera ser implementado utilizando llamadas a las bibliotecas estándar. Así que eres una especie de fuera de suerte a menos que lo tienes.

Otros consejos

mktime tarda un tiempo en la zona horaria local. Por lo tanto, si se le pasa 1970-01-01 00:00:00 hora local , devuelve 1970-01-01 06:00:00 UTC , como debería .

Como alternativa, puede llamar timegm , si utiliza glibc. Si usted no está usando glibc, cambiar temporalmente la hora local a UTC cuando se llama a mktime por jugar con la variable de entorno TZ, tal como se describe en la página de manual timegm:

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;
}

Además, su llamada a localtime es innecesaria, y probablemente debería conjunto given_time->tm_isdst, para evitar posibles problemas de horario de verano.

Tal vez se debe utilizar en lugar de gmtime time, para librarse de los problemas de zona horaria.

Editar Realmente no entiendo por qué llenar la estructura con la hora actual, a continuación, sobrescribir todos sus componentes. ¿Por qué no simplemente:

time_t get_unix_time(const string& time_str)
{
    vector<string> trecord = split_string(time_str, ',');

    tm given_time;
    given_time.tm_year = atoi(trecord.at(0).c_str()) - 1900;
    given_time.tm_mon  = atoi(trecord.at(1).c_str()) - 1;
    given_time.tm_mday = atoi(trecord.at(2).c_str());
    given_time.tm_hour = atoi(trecord.at(3).c_str());
    given_time.tm_min  = atoi(trecord.at(4).c_str());
    given_time.tm_sec  = atoi(trecord.at(5).c_str());

    return mktime(&given_time);
}

Otra edición:

Uf, mktime considera hora local también. No estoy muy seguro de cómo se puede conseguir alrededor de esto aparte de establecer la configuración regional zona horaria a UTC.

Sólo evitar estas funciones incómodas y hacer sus propios cálculos. POSIX especifica que time_t es un tipo aritmético en forma de segundos, ya que "la época" (1970-01-01 00:00:00 GMT) sin ningún disparate segundo intercalar (todos los días son exactamente 86400 segundos calendario , que difieren de SI segundos por una pequeña cantidad), por lo que aparte de un poco de lógica leapyear, el cálculo es muy sencillo.

cálculos del calendario como este son un ejercicio de introducción a la programación estándar, así que estoy seguro de que podemos hacer algo o encontrar soluciones en la web.

Como acotación al margen, tal vez la razón ISO C y POSIX omitir una función de este tipo es que, a diferencia de las conversiones que implican husos horarios que pueden ser arbitrariamente compleja y que sólo la biblioteca del host puede realizar de forma fiable y consistente a través de diferentes aplicaciones, las conversiones GMT son pura aritmética sin parámetros externos.

Cuando se llama a mktime, que interpretes el parámetro como una hora local. También tienen una función como la "hora local", que parece ser inútil utilizado y yo creo que se pueda caer.

Se puede escribir una envoltura alrededor de strptime para hacer el análisis.

struct tm given_time;

strptime(time_str.c_str(), "%Y-%m-%d %H:%M:%S", &given_time);

return mktime(&given_time);

La respuesta de @ Josh Kelley explica el problema zona horaria a fondo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top