steady_clock c++ c++11 unix-timestamp chrono

steady_clock - chrono en c++



Convertir std:: chrono:: time_point a unix timestamp (3)

¿Cómo puedo obtener una std::chrono::duration desde una fecha fija? Necesito esto para convertir un std::chrono::time_point en una marca de tiempo de Unix.

Insertar código en XXX

auto unix_epoch_start = XXX; auto time = std::chrono::system_clock::now(); auto delta = time - unix_epoc_start; auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(delta).count();

Sé que time_point tiene un método time_since_epoch() pero no está garantizado que este sea el mismo que la época de Unix (00:00:00 UTC el 1 de enero de 1970).


En pocas palabras, aquí está la función que uso para obtener la marca de tiempo de Unix (segundos desde el 1 de enero de 1970 UTC):

static uint64_t getUnixTimeStamp(const std::time_t* t = nullptr) { //if specific time is not passed then get current time std::time_t st = t == nullptr ? std::time(nullptr) : *t; auto secs = static_cast<std::chrono::seconds>(st).count(); return static_cast<uint64_t>(secs); }

La ventaja de esta función es que el valor predeterminado del parámetro solo le da la hora actual. Sin embargo, si desea convertir un tiempo específico en la marca de tiempo de Unix, también puede hacerlo.


Podría usar mktime() para convertir la fecha deseada codificada en una estructura tm en un valor time_t hora local .

Si necesita un tiempo UTC, entonces use gmttime() para convertir ese valor time_t en una estructura gmttime() UTC, y gmttime() de la salida que obtiene qué estructura tm produce el tiempo UTC deseado cuando se mktime() en mktime() .

Un poco elaborado, pero con suerte funcionará o al menos proporcionará una pista.


Una marca de tiempo de Unix se define como el número de segundos desde el 1 de enero de 1970 UTC, excepto que no se cuentan todos los segundos. Esto es algo ridículo y uno tiene que preguntarse de qué se trata, así que estoy de acuerdo en que esta es una pregunta tonta.

De todos modos, veamos algunos documentos de la plataforma para time_t y time() .

Linux :

time () devuelve el tiempo como el número de segundos desde la Época, 1970-01-01 00:00:00 +0000 (UTC).

POSIX.1 define segundos desde la Época usando una fórmula que se aproxima al número de segundos entre un tiempo especificado y la Época. Esta fórmula tiene en cuenta que todos los años divisibles uniformemente por 4 son años bisiestos, pero los años divisibles equitativamente por 100 no son años bisiestos, a menos que también sean divisibles equitativamente por 400, en cuyo caso son años bisiestos. Este valor no es el mismo que el número real de segundos entre el tiempo y la época, debido a los segundos de salto y porque no es necesario que los relojes del sistema estén sincronizados con una referencia estándar. La intención es que la interpretación de segundos desde los valores de Época sea consistente; ver POSIX.1-2008 Justificación A.4.15 para una explicación más detallada.

Windows :

La función de hora devuelve el número de segundos transcurridos desde la medianoche (00:00:00), 1 de enero de 1970, Tiempo Universal Coordinado (UTC), según el reloj del sistema.

Mac OS X :

Las funciones ctime (), gmtime () y localtime () toman como argumento un valor de tiempo que representa el tiempo en segundos desde la Época (00:00:00 UTC, 1 de enero de 1970;

Las funciones asctime (), ctime (), difftime (), gmtime (), localtime () y mktime () cumplen con ISO / IEC 9899: 1990 ( ISO C90''''), and conform to ISO/IEC 9945-1:1996 ( POSIX.1 '''') siempre que la zona horaria local seleccionada no contenga una tabla de segundos de salto (consulte zic (8)).

Puede encontrar documentación similar para otros sistemas, como AIX, HP-UX, Solaris, etc.

Entonces, aunque no está especificado en C ++, hay una manera fácil y ampliamente portátil de obtener una marca de tiempo Unix:

auto unix_timestamp = std::chrono::seconds(std::time(NULL));

Y si desea una cantidad de milisegundos desde el 1 de enero de 1970 UTC (de manera similar, sin contarlos todos), puede hacer esto:

int unix_timestamp_x_1000 = std::chrono::milliseconds(unix_timestamp).count();

Solo recuerde que estos valores no son tiempos reales, por lo que en general no puede usar marcas de tiempo de Unix en aritmética. Por ejemplo, restar las marcas de tiempo de Unix no le da un conteo preciso de segundos entre los tiempos. O si hiciste algo como:

std::chrono::steady_clock::now() - unix_timestamp;

no obtendría un punto de tiempo correspondiente a 1970-01-01 00: 00: 00 + 0000.

Como Andy Prowl sugiere que podrías hacer algo tonto como:

// 1 Jan 1970 (no time zone) std::tm c = { 0, 0, 0, 1, 0, 70, 0, 0, -1}; // treat it as 1 Jan 1970 (your system''s time zone) and get the // number of seconds since your system''s epoch (leap seconds may // or may not be included) std::time_t l = std::mktime(&c); // get a calender time for that time_point in UTC. When interpreted // as UTC this represents the same calendar date and time as the // original, but if we change the timezone to the system TZ then it // represents a time offset from the original calendar time by as // much as UTC differs from the local timezone. std::tm m = *std::gmtime(&l); // Treat the new calendar time as offset time in the local TZ. Get // the number of seconds since the system epoch (again, leap seconds // may or may not be counted). std::time_t n = std::mktime(&m); l -= (n-l); // subtract the difference

Ahora debería representar el número de segundos (incorrecto) desde el 1 de enero de 1970 UTC. Siempre que no haya segundos de salto entre la época del sistema y el 1 de enero de 1970 (zona horaria del sistema), o dentro de un período de tiempo igual en la otra dirección desde la época del sistema, cualquier segundo salto del segundo contado se cancelará y l será mal de la misma manera que las marcas de tiempo de Unix son incorrectas.

Otra opción es usar una biblioteca de fechas decentes como el cronógrafo de Howard Hinnant chrono::date . (Howard Hinnant fue uno de los muchachos que trabajó en la biblioteca <chrono> ++ <chrono> C ++ 11).

auto now = system_clock::now(); sys_days today = time_point_cast<days>(now); system_clock::time_point this_morning = today; sys_days unix_epoch = day(1)/jan/1970; days days_since_epoch = today - unix_epoch; auto s = now - this_morning; auto tz_offset = hours(0); int unix_timestamp = (days_since_epoch + s + tz_offset) / seconds(1);

Si desea manejar segundos de salto, Howard Hinnant también proporciona una biblioteca que incluye instalaciones para manejarlos, así como para analizar bases de datos de zonas horarias como la fuente de los segundos de salto.