Como obter a hora atual em milissegundos de C no Linux?


86

Como obtenho a hora atual no Linux em milissegundos?

Respostas:


100

Isso pode ser feito usando a função POSIXclock_gettime .

Na versão atual do POSIX, gettimeofdayestá marcado como obsoleto . Isso significa que pode ser removido de uma versão futura da especificação. Os criadores de aplicativos são incentivados a usar a clock_gettimefunção em vez de gettimeofday.

Aqui está um exemplo de como usar 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);
}

Se o seu objetivo é medir o tempo decorrido e o seu sistema suporta a opção "relógio monotônico", então você deve considerar o uso em CLOCK_MONOTONICvez de CLOCK_REALTIME.


7
+1 por estar POSIXly correto - mas sua resposta tem unidades erradas. O OP não quer o tempo em milissegundos, mas o tempo em milissegundos.
pilcrow

5
Boa solução, mas não se esqueça do -lm em seu gcccomando.
David Guyon

2
de acordo com a página de manual para round, você deseja usar lround ao atribuir o resultado a um número inteiro (ou longo)
hildred

2
Você precisa usar floor () em vez de round () para que nunca chegue a 1000 ms. Caso contrário, você precisará incrementar squando isso acontecer. Provavelmente um evento raro, mas o dígito extra pode causar problemas.
Mike

1
@Mike Nice catch. Em um em dois mil, não é tão raro, então definitivamente deve ser corrigido. Em vez de usar piso, acho que prefiro manter um pouco mais de precisão e continuar arredondando, mas incrementar o segundo contador se ele arredondar para 1000.
Dan Molding

58

Você tem que fazer algo assim:

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

33

A seguir está a função util para obter o carimbo de data / hora atual em milissegundos:

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

Sobre o fuso horário :

Suporte gettimeofday () para especificar fuso horário, eu uso NULL , que ignora o fuso horário, mas você pode especificar um fuso horário, se necessário.


@Update - fuso horário

Uma vez que a longrepresentação do tempo não é relevante ou efetuada pelo próprio fuso horário, definir o tzparâmetro gettimeofday () não é necessário, pois não fará nenhuma diferença.

E, de acordo com a página de manual de gettimeofday(), o uso da timezoneestrutura é obsoleto, portanto, o tzargumento normalmente deve ser especificado como NULL, para obter detalhes, verifique a página de manual.


1
> suporte gettimeofday () para especificar fuso horário, eu uso NULL, que ignora o fuso horário, mas você pode especificar um fuso horário, se necessário. Você está errado. O fuso horário deve ser introduzido exclusivamente por meio da chamada para localtime ().
vitaly.v.ch

@ vitaly.v.ch Fiz um teste, passando no tzparâmetro de gettimeofday()como &(struct timezone tz = {480, 0})não recebo nenhum aviso, e não surte efeito no resultado, faz sentido, já que a longrepresentação do tempo não é relevante ou efetuada pelo próprio fuso horário, certo?
Eric Wang

Não havia razão para fazer nenhum teste. O kernel do Linux não tem informações adequadas sobre fusos horários e, ao mesmo tempo, não tem como fornecê-las. É uma razão pela qual o argumento tz é processado de maneira muito específica. representação longa não importa.
vitaly.v.ch

@ vitaly.v.ch Em um ponto de tempo específico, a representação longa não varia devido ao fuso horário, por isso é importante, e por isso normalmente só NULLé o valor razoável a passar. E acredito que testar é sempre uma boa abordagem para provar coisas.
Eric Wang



0

Derivado da resposta POSIX de Dan Moulding, isso deve 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);
}

Também como apontado por David Guyon: compilar com -lm

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.