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

86

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

LLL
źródło

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.

Dan Moulding
źródło
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
yadab
źródło
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.

Eric Wang
źródło
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
13

Użyj, gettimeofday()aby uzyskać czas w sekundach i mikrosekundach. Łączenie i zaokrąglanie do milisekund pozostaje jako ćwiczenie.

Donal Fellows
źródło
7

C11 timespec_get

Powraca do nanosekund, zaokrąglając do rozdzielczości implementacji.

Jest już zaimplementowany w Ubuntu 15.10. API wygląda tak samo jak 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 */
};

Więcej szczegółów tutaj: https://stackoverflow.com/a/36095407/895245

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło
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

Jirka Justra
źródło