2010-04-15 2 views
2

Мне нужно вычислить метку времени ntp, используя gettimeofday. Ниже приведен пример того, как я это сделал с комментариями к методу. Хорошо выглядеть вам, ребята? (минус проверка ошибок). Кроме того, вот ссылка codepad.Создайте временную метку ntp с gettimeofday

#include <unistd.h> 
#include <sys/time.h> 

const unsigned long EPOCH = 2208988800UL; // delta between epoch time and ntp time 
const double NTP_SCALE_FRAC = 4294967295.0; // maximum value of the ntp fractional part 

int main() 
{ 
    struct timeval tv; 
    uint64_t ntp_time; 
    uint64_t tv_ntp; 
    double tv_usecs; 

    gettimeofday(&tv, NULL); 
    tv_ntp = tv.tv_sec + EPOCH; 

    // convert tv_usec to a fraction of a second 
    // next, we multiply this fraction times the NTP_SCALE_FRAC, which represents 
    // the maximum value of the fraction until it rolls over to one. Thus, 
    // .05 seconds is represented in NTP as (.05 * NTP_SCALE_FRAC) 
    tv_usecs = (tv.tv_usec * 1e-6) * NTP_SCALE_FRAC; 

    // next we take the tv_ntp seconds value and shift it 32 bits to the left. This puts the 
    // seconds in the proper location for NTP time stamps. I recognize this method has an 
    // overflow hazard if used after around the year 2106 
    // Next we do a bitwise OR with the tv_usecs cast as a uin32_t, dropping the fractional 
    // part 
    ntp_time = ((tv_ntp << 32) | (uint32_t)tv_usecs); 
} 
+0

Могу ли я спросить, почему вы умножаете tv_usec с NTP_SCALE_FRAC? для меня, кажется, trasnforming usec для pico секунд (* 10^6) должно быть достаточно, может быть, я чего-то не хватает? – 2010-05-19 16:34:18

+1

В NTP, если я правильно понимаю, часть дроби представляется в виде доли от всех возможных значений. Так что это не 1 к 1. Например, если я представляю одну секунду в 1000 частях, то кто-то дает мне значение 0,5 секунды с базой 60, мне придется масштабировать ее до моей базы 1000. С NTP базой является 32-битное представление, в которое оно преобразуется. Итак, 1 секунда = 2^32 ntp доли секунды. – jkyle

+0

Спасибо, я это понимаю. Для меня не очевидно, почему tv_usecs = (NTP_SCALE_FRAC * tv.tv_usec)/1000000UL выполняет эту работу? – 2010-05-20 12:20:59

ответ

0

Там нет необходимости использовать uint64_t здесь - unsigned long long гарантированно будет по крайней мере 64 бита.

Вам также не нужно идти от double, так как NTP_SCALE_FRAC * 1000000 легко поместится в unsigned long long.

EPOCH должно быть unsigned long long, а не unsigned long, так что добавление с tv.tv_sec не обертывается.

Все до:

const unsigned long long EPOCH = 2208988800ULL; 
const unsigned long long NTP_SCALE_FRAC = 4294967295ULL; 

unsigned long long tv_to_ntp(struct timeval tv) 
{ 
    unsigned long long tv_ntp, tv_usecs; 

    tv_ntp = tv.tv_sec + EPOCH; 
    tv_usecs = (NTP_SCALE_FRAC * tv.tv_usec)/1000000UL; 

    return (tv_ntp << 32) | tv_usecs; 
} 
+1

Возможно, я ошибаюсь, но спецификация долгое время заключается в том, что она не менее 64, но может быть больше. Мне нужно выполнить некоторую байтовую замену результатов (порядок сетевого байта), поэтому я хотел более жестко ограничить размер. – jkyle

+0

Да, это может быть больше. Если вам нужно манипулировать базовым представлением (например, чтобы передать его в сетевой пакет), то использование 'uint64_t' является подходящим, но вы, как правило, должны ограничивать это использование для работы с упаковкой/распаковкой кода. – caf

+2

Выкл. 1. 'NTP_SCALE_FRAC' должно быть' 4294967296ULL', или даже лучше просто использовать 'tv_usecs = ((unsigned long long) tv.tv_usec << 32)/1000000ULL;'. – mark4o

1
extern uint64_t tvtontp64(struct timeval *tv) { 
    uint64_t ntpts; 

    ntpts = (((uint64_t)tv->tv_sec + 2208988800u) << 32) + ((uint32_t)tv->tv_usec * 4294.967296); 

    return (ntpts); 
} 

Я использую 4294,967296 не ... 5, как это отношение к общему количеству 0 потребности быть подсчитаны 4294967296 тиков в секунду или 4294.967296 за мксек его просто проверить это как 1000000 usec будет переполнение [в секундах] диапазон тиков должен быть от 0 до (1000000-1).

Это упрощение и подходит для моей цели Unique Local IPv6 Unicast Адреса [RFC4193]

Смежные вопросы