Як отримати поточний час у мілісекундах з C в Linux?


86

Як отримати поточний час на Linux в мілісекундах?

Відповіді:


100

Цього можна досягти за допомогою функції POSIXclock_gettime .

У поточній версії POSIX, gettimeofdayбуде відзначений застарілими . Це означає, що він може бути вилучений із майбутньої версії специфікації. Авторам додатків рекомендується використовувати clock_gettimeфункцію замість gettimeofday.

Ось приклад використання 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);
}

Якщо ваша мета - виміряти минулий час, і ваша система підтримує опцію "монотонний годинник", вам слід подумати про використання CLOCK_MONOTONICзамість CLOCK_REALTIME.


7
+1 за правильність POSIXly, але ваша відповідь містить неправильні одиниці виміру. OP не хоче часу з мілісекундами, а часу в мілісекундах.
pilcrow

5
Хороше рішення , але не забувайте -lm у вашій gccкоманді.
Девід Гуйон,

2
відповідно до сторінки сторінки для раунду, ви хочете використовувати lround при призначенні результату до цілого (або довгого)
hildred

2
Вам потрібно використовувати floor () замість round (), щоб він ніколи не округлявся до 1000 мс. В іншому випадку вам потрібно буде збільшити, sколи це станеться. Можливо, рідкісна подія, але зайва цифра може спричинити проблеми.
Mike

1
@Mike Приємний улов. У кожній другій тисячі це навіть не настільки рідко, тому це точно слід виправити. Замість того, щоб використовувати підлогу, я вважаю за краще зберегти трохи більше точності і продовжувати округляти, але збільшувати другий лічильник, якщо він округлюється до 1000.
Ден Молдінг

58

Ви повинні зробити щось подібне:

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

Нижче наведена функція util для отримання поточної позначки часу в мілісекундах:

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

Про часовий пояс :

Підтримка gettimeofday () для вказівки часового поясу, я використовую NULL , який ігнорує часовий пояс, але ви можете вказати часовий пояс, якщо потрібно.


@Оновити - часовий пояс

Оскільки longподання часу не має значення або не tzвпливає на сам часовий пояс, тому встановлення параметра gettimeofday () не є необхідним, оскільки це не призведе до різниці.

І, відповідно до man сторінки gettimeofday(), використання timezoneструктури застаріло, тому tzаргумент, як правило, повинен бути вказаний як NULL, для деталей перевірте man сторінку.


1
> підтримка gettimeofday () для вказівки часового поясу, я використовую NULL, який ігнорує часовий пояс, але ви можете вказати часовий пояс, якщо потрібно. Ви неправі. Часовий пояс слід вводити виключно за допомогою дзвінка в localtime ().
vitaly.v.ch

@ vitaly.v.ch Я провів тест, пройшовши tzпараметр gettimeofday()як &(struct timezone tz = {480, 0})не отримає жодного попередження, і це ніяк не впливає на результат, що має сенс, оскільки longподання часу не має відношення до або здійснюється за самим часовим поясом, так?
Eric Wang

Не було жодної причини робити будь-який тест. Ядро Linux не має належної інформації про часові пояси і в той же час не має способу її надати. Це причина, чому аргумент tz обробляється дуже конкретно. тривале представництво не має значення.
vitaly.v.ch

@ vitaly.v.ch У конкретний момент часу тривале представлення не змінюється залежно від часового поясу, тому це має значення, і завдяки цьому, як правило, NULLпотрібно прийняти лише розумне значення. І, я вважаю, тестування - це завжди хороший підхід для доведення речей.
Eric Wang

13

Використовуйте gettimeofday()для отримання часу в секундах і мікросекундах. Поєднання та округлення до мілісекунд залишається як вправа.


7

C11 timespec_get

Він повертається до наносекунд, округлених до роздільної здатності реалізації.

Це вже реалізовано в Ubuntu 15.10. API виглядає так само, як 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 */
};

Детальніше тут: https://stackoverflow.com/a/36095407/895245


0

Отримано з відповіді POSIX Дена Молдінга, це повинно працювати:

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

Також, як зазначив Девід Гайон: компілюйте за допомогою -lm

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.