¿Cómo obtener la hora actual en milisegundos de C en Linux?

86

¿Cómo obtengo la hora actual en Linux en milisegundos?

LLL
fuente

Respuestas:

100

Esto se puede lograr utilizando la función POSIXclock_gettime .

En la versión actual de POSIX, gettimeofdayestá marcado como obsoleto . Esto significa que puede eliminarse de una versión futura de la especificación. Se anima a los escritores de aplicaciones a utilizar la clock_gettimefunción en lugar de gettimeofday.

A continuación, se muestra un ejemplo de cómo utilizarlo clock_gettime:

#define _POSIX_C_SOURCE 200809L

#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include <time.h>

void print_current_time_with_ms (void)
{
    long            ms; // Milliseconds
    time_t          s;  // Seconds
    struct timespec spec;

    clock_gettime(CLOCK_REALTIME, &spec);

    s  = spec.tv_sec;
    ms = round(spec.tv_nsec / 1.0e6); // Convert nanoseconds to milliseconds
    if (ms > 999) {
        s++;
        ms = 0;
    }

    printf("Current time: %"PRIdMAX".%03ld seconds since the Epoch\n",
           (intmax_t)s, ms);
}

Si su objetivo es medir el tiempo transcurrido y su sistema admite la opción "reloj monótono", debería considerar usar en CLOCK_MONOTONIClugar de CLOCK_REALTIME.

Moldeo Dan
fuente
7
+1 por ser POSIX correctamente correcto, pero su respuesta tiene las unidades incorrectas. El OP no quiere el tiempo en milisegundos, sino el tiempo en milisegundos.
Pilcrow
5
Buena solución, pero no olvide el -lm en su gcccomando.
David Guyon
2
de acuerdo con la página de manual de round, desea usar lround al asignar el resultado a un entero (o largo)
hildred
2
Necesita usar floor () en lugar de round () para que nunca se redondea a 1000 ms. De lo contrario, necesitaría incrementar scuando esto ocurra. Probablemente sea un evento poco común, pero el dígito extra puede causar problemas.
Mike
1
@ Mike Niza captura. En uno de cada dos mil, ni siquiera es tan raro, por lo que definitivamente debería arreglarse. En lugar de usar el piso, creo que preferiría mantener un poco más de precisión y continuar redondeando, pero incrementar el segundo contador si se redondea a 1000.
Dan Molding
58

Tienes que hacer algo como esto:

struct timeval  tv;
gettimeofday(&tv, NULL);

double time_in_mill = 
         (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; // convert tv_sec & tv_usec to millisecond
yadab
fuente
33

A continuación se muestra la función util para obtener la marca de tiempo actual en milisegundos:

#include <sys/time.h>

long long current_timestamp() {
    struct timeval te; 
    gettimeofday(&te, NULL); // get current time
    long long milliseconds = te.tv_sec*1000LL + te.tv_usec/1000; // calculate milliseconds
    // printf("milliseconds: %lld\n", milliseconds);
    return milliseconds;
}

Acerca de la zona horaria :

Soporte de gettimeofday () para especificar la zona horaria, yo uso NULL , que ignora la zona horaria, pero puede especificar una zona horaria, si es necesario.


@Update - zona horaria

Dado que la longrepresentación del tiempo no es relevante ni se ve afectada por la zona horaria en sí, tzno es necesario establecer el parámetro de gettimeofday (), ya que no hará ninguna diferencia.

Y, de acuerdo con la página de manual de gettimeofday(), el uso de la timezoneestructura es obsoleto, por lo que el tzargumento normalmente debe especificarse como NULL; para obtener más detalles, consulte la página de manual.

Eric Wang
fuente
1
> Soporte para gettimeofday () para especificar la zona horaria, yo uso NULL, que ignora la zona horaria, pero puede especificar una zona horaria, si es necesario. Está usted equivocado. La zona horaria debe introducirse exclusivamente mediante una llamada a localtime ().
vitaly.v.ch
@ vitaly.v.ch Hice una prueba, pasando el tzparámetro de gettimeofday()as &(struct timezone tz = {480, 0})no recibirá ninguna advertencia, y no tiene ningún efecto en el resultado, eso tiene sentido, ya que la longrepresentación del tiempo no es relevante ni se efectúa por zona horaria en sí, ¿verdad?
Eric Wang
No había razón para hacer ninguna prueba. El kernel de Linux no tiene la información adecuada sobre las zonas horarias y, al mismo tiempo, no tiene una forma de proporcionarla. Es una razón por la que el argumento tz se procesa de una manera muy específica. la representación larga no importa.
vitaly.v.ch
@ vitaly.v.ch En un punto de tiempo específico, la representación larga no varía debido a la zona horaria, por eso es importante, y debido a eso, normalmente solo se NULLpasa el valor razonable. Y creo que las pruebas siempre son un buen enfoque para probar las cosas.
Eric Wang
13

Úselo gettimeofday()para obtener el tiempo en segundos y microsegundos. La combinación y el redondeo a milisegundos se deja como ejercicio.

Becarios Donales
fuente
7

C11 timespec_get

Vuelve a nanosegundos, redondeado a la resolución de la implementación.

Ya está implementado en Ubuntu 15.10. API tiene el mismo aspecto que POSIX clock_gettime.

#include <time.h>
struct timespec ts;
timespec_get(&ts, TIME_UTC);
struct timespec {
    time_t   tv_sec;        /* seconds */
    long     tv_nsec;       /* nanoseconds */
};

Más detalles aquí: https://stackoverflow.com/a/36095407/895245

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
0

Derivado de la respuesta POSIX de Dan Moulding, esto debería funcionar:

#include <time.h>
#include <math.h>

long millis(){
    struct timespec _t;
    clock_gettime(CLOCK_REALTIME, &_t);
    return _t.tv_sec*1000 + lround(_t.tv_nsec/1.0e6);
}

También como lo señaló David Guyon: compile con -lm

Jirka Justra
fuente