Jak uzyskać bieżący czas w milisekundach z C w systemie Linux?


86

Jak uzyskać bieżący czas w systemie Linux w milisekundach?

Odpowiedzi:


100

Można to osiągnąć za pomocą funkcji POSIXclock_gettime .

W aktualnej wersji POSIX gettimeofdayjest oznaczony jako przestarzały . Oznacza to, że może zostać usunięty z przyszłej wersji specyfikacji. Zachęcamy autorów aplikacji do używania clock_gettimefunkcji zamiast gettimeofday.

Oto przykład użycia 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);
}

Jeśli Twoim celem jest pomiar czasu, który upłynął, a Twój system obsługuje opcję „zegara monotonicznego”, powinieneś rozważyć użycie CLOCK_MONOTONICzamiast CLOCK_REALTIME.


7
+1 za bycie POSIXly poprawnym - ale twoja odpowiedź zawiera niewłaściwe jednostki. OP nie chce czasu w milisekundach, ale czas w milisekundach.
pilcrow

5
Dobre rozwiązanie, ale nie zapomnij o opcji -lm w gccpoleceniu.
David Guyon

2
zgodnie ze stroną podręcznika dla round, chcesz użyć lround podczas przypisywania wyniku do liczby całkowitej (lub długiej)
hildred

2
Musisz użyć floor () zamiast round (), aby nigdy nie zaokrąglało do 1000 ms. W przeciwnym razie będziesz musiał zwiększyć, skiedy to nastąpi. Prawdopodobnie rzadkie zdarzenie, ale dodatkowa cyfra może powodować problemy.
Mike

1
@Mike Niezły chwyt. Jeden na dwa tysiące nie jest nawet taki rzadki, więc zdecydowanie powinien zostać naprawiony. Zamiast używać podłogi, myślę, że wolałbym zachować nieco większą dokładność i kontynuować zaokrąglanie, ale zwiększając drugi licznik, jeśli zaokrągla się do 1000.
Dan Molding,

58

Musisz zrobić coś takiego:

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

Poniżej znajduje się funkcja util do pobierania aktualnego znacznika czasu w milisekundach:

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

O strefie czasowej :

gettimeofday (), aby określić strefę czasową, używam wartości NULL , która ignoruje strefę czasową, ale w razie potrzeby możesz określić strefę czasową.


@Update - strefa czasowa

Ponieważ longreprezentacja czasu nie jest związana z samą strefą czasową ani nie ma przez nią wpływu, więc ustawienie tzparametru gettimeofday () nie jest konieczne, ponieważ nie będzie miało żadnego znaczenia.

I według człowieka stronie gettimeofday(), wykorzystanie timezonestruktury jest przestarzały, więc tzargument powinien być zazwyczaj określone jako NULL, szczegóły proszę sprawdzić na stronie man.


1
> obsługa gettimeofday () w celu określenia strefy czasowej, używam NULL, które ignorują strefę czasową, ale w razie potrzeby możesz określić strefę czasową. Mylisz się. Strefę czasową należy wprowadzić wyłącznie poprzez wywołanie localtime ().
vitaly.v.ch

@ vitaly.v.ch Zrobiłem test, przekazując tzparametr gettimeofday()as &(struct timezone tz = {480, 0}), nie otrzymam żadnego ostrzeżenia i nie ma to żadnego wpływu na wynik, to ma sens, ponieważ longreprezentacja czasu nie ma znaczenia ani nie ma wpływu według samej strefy czasowej, prawda?
Eric Wang

Nie było powodu, żeby robić jakiekolwiek testy. Jądro Linuksa nie ma odpowiednich informacji o strefach czasowych, a jednocześnie nie ma sposobu na ich dostarczenie. Jest to powód, dla którego argument tz jest przetwarzany w bardzo specyficzny sposób. długa reprezentacja nie ma znaczenia.
vitaly.v.ch

@ vitaly.v.ch W określonym momencie, długa reprezentacja nie zmienia się ze względu na strefę czasową, dlatego ma to znaczenie iz tego powodu zwykle NULLjest tylko rozsądna wartość do przekazania. Uważam, że testowanie jest zawsze dobrym podejściem do udowodnienia rzeczy.
Eric Wang



0

Pochodzący z odpowiedzi POSIX Dana Mouldinga, to powinno działać:

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

Również, jak wskazał David Guyon: skompiluj z -lm

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.