2010-04-15 55 views
2

我需要使用gettimeofday來計算ntp時間戳。以下是我對方法的評論。看起來很好,你們呢? (減去錯誤檢查)。此外,這是一個codepad鏈接。從gettimeofday創建ntp時間戳

#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

我可以問你爲什麼用NTP_SCALE_FRAC乘tv_usec?對我來說,似乎將pico秒(* 10^6)轉換爲usec可能就足夠了,也許我錯過了一些東西? – 2010-05-19 16:34:18

+1

在NTP中,如果我理解正確,分數部分將表示爲總可能值的一小部分。所以這不是1比1。例如,如果我代表1000秒中的一秒鐘,那麼有人給我一個0.5秒的值,基數爲60,我必須將其縮放到我的基數1000. 使用NTP時,基數是它轉換成的32位表示。所以1秒= 2^32 ntp分數秒。 – jkyle 2010-05-19 17:59:11

+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 2010-04-15 03:25:29

+0

是的,它可能更多。如果你需要操作底層表示(比如將其填充到網絡數據包中),那麼使用'uint64_t'是適當的,但是你通常應該將這種使用限制在網絡處理打包/解包代碼本身。 – caf 2010-04-15 03:50:02

+2

關閉1.'NTP_SCALE_FRAC'應該是'4294967296ULL',或者甚至更好使用'tv_usecs =(((無符號long long)tv.tv_usec << 32)/ 1000000ULL;'。 – mark4o 2012-05-11 00:45:23

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)。

這是我的目的簡化和適當 當地獨特的IPv6單播地址[RFC4193]