2017-02-23 110 views
0

我需要根據 RFC 5905由以下結構表示爲boost::posix_time::ptime轉換成NTP 日期郵票:轉換的boost ::了posix_time ::的ptime到NTP時間戳

struct NtpDatestamp { 
    std::int32_t era_number; 
    std::uint32_t seconds_since_era_epoch; 
    std::uint64_t fraction_of_second; 
}; 

RFC 5905條規定如下:

要轉換系統時間以任何形式向NTP日期和時間戳的格式 要求從黃金時期秒s到系統0號時間確定。爲了確定整數eratimestamp給出s

era = s/2^(32) and timestamp = s - era * 2^(32), 

它適用於正面和負面的日期。爲了確定給定的時代 和時間戳s

s = era * 2^(32) + timestamp. 

所以我嘗試了以下內容:

const auto system_time = boost::posix_time::time_from_string("1899-12-31 00:00:00.000"); 

const boost::posix_time::ptime prime_epoch{boost::gregorian::date{1900, 1, 1}}; 
// Calculate the number of seconds from the prime epoch to the system time. 
const boost::posix_time::time_duration time_duration{system_time - prime_epoch}; 
const std::int64_t s{time_duration.total_seconds()}; 
const std::int32_t era_number{static_cast<std::int32_t>(s/std::pow(2, 32))}; 
const std::uint64_t seconds_since_era_epoch{static_cast<std::uint64_t>(s - s/std::pow(2, 32) * std::pow(2, 32))}; 
// The fraction of a NTP Datestamp is measured in Attoseconds. 
const std::uint64_t fraction_of_second{static_cast<std::uint64_t>(time_duration.total_microseconds() * 1e12)}; 

但是,讓不正確的結果。

我完全被這個(其實很簡單)的問題困擾着。

有人可以引導我進入正確的方向嗎?我如何獲得時代號碼,時代補償分數 NTP日期戳boost::posix_time::ptime

編輯: RFC 5905中的計算不夠準確,或者我誤解了它們。多虧了意見,我已經改變了計算如下(此時一個完整的例子):

#include <cmath> 
#include <cstdint> 
#include <iostream> 

#include <boost/date_time.hpp> 

int main() { 
    const auto system_time = 
     boost::posix_time::time_from_string("1899-12-31 00:00:00.000"); 

    const boost::posix_time::ptime prime_epoch{ 
     boost::gregorian::date{1900, 1, 1}}; 
    // Calculate the number of seconds from the prime epoch to the system time. 
    const boost::posix_time::time_duration time_duration{prime_epoch - 
                 system_time}; 

    // s is correctly determined now. 
    std::int64_t s{time_duration.total_seconds()}; 
    if (prime_epoch > system_time) { 
    // boost::posix_time::time_duration does not take the sign into account. 
    s *= -1; 
    } 

    // TODO(wolters): The following calculations do not return the correct 
    // results, but the RFC 5905 states them 
    const std::int32_t era{static_cast<std::int32_t>(s/std::pow(2, 32))}; 
    const std::uint64_t timestamp{ 
     static_cast<std::uint64_t>(s - era * std::pow(2, 32))}; 
    // The fraction of a NTP Datestamp is measured in Attoseconds. 
    // TODO(wolters): `boost::posix_time::ptime` does NOT resolve to attoseconds, 
    // but doesn't the target format expect the value to be specified as 
    // attoseconds? Doesn't the following depend on Boost compile options? 
    const std::uint64_t fraction{ 
     static_cast<std::uint64_t>(time_duration.fractional_seconds())}; 

    std::cout << "s = " << std::dec << s << '\n'; 
    // TODO(wolters): This does still not match the expected results; taken from 
    // Figure 4 of https://www.ietf.org/rfc/rfc5905.txt 
    std::cout << "Era (expected: -1) = " << std::dec << era << '\n'; 
    std::cout << "Timestamp (expected: 4294880896) = " << std::dec << timestamp 
      << '\n'; 
    std::cout << "Fraction (expected: 0) = " << std::dec << fraction << '\n'; 
} 

s現在可以正確地計算,但其他的計算是錯誤的。我想我完全錯過了一些重要的東西......

+1

一個問題:seconds_since_era_epoch應該計算的S - era_number * 2^32,但你計算的方式,它會永遠是零。 – lrm29

+0

第二個問題:fraction_of_second應該使用time_duration.fractional_seconds() 第三個問題:ptime無法解析爲attoseconds ... – lrm29

回答

0

看來我已經找出了自己缺失的部分。我在可重用類ntp::Datestamp中實現了以下算法,並且單元使用RFC 5905的參考日期對其進行了測試。所有測試最終都是綠色的。這裏是解決方案:

#include <cmath> 
#include <cstdint> 
#include <ctime> 
#include <iostream> 

#include <boost/date_time.hpp> 

static std::time_t to_time(const boost::posix_time::ptime& time) { 
    static const boost::posix_time::ptime epoch_time{ 
     boost::gregorian::date{1970, 1, 1}}; 
    const boost::posix_time::time_duration diff{time - epoch_time}; 

    return (diff.ticks()/diff.ticks_per_second()); 
} 

int main() { 
    const auto system_time = 
     boost::posix_time::time_from_string("1899-12-31 00:00:00.123"); 
    const boost::posix_time::ptime prime_epoch{ 
     boost::gregorian::date{1900, 1, 1}}; 
    // Calculate the number of seconds from the prime epoch to the system time. 
    std::time_t s{to_time(system_time) - to_time(prime_epoch)}; 

    const std::int32_t era{static_cast<std::int32_t>(std::floor(s/std::pow(2, 32)))}; 
    const std::uint32_t timestamp{ 
     static_cast<std::uint32_t>(s - era * std::pow(2, 32))}; 
    const std::uint64_t fraction{static_cast<std::uint64_t>(
     system_time.time_of_day().fractional_seconds())}; 

    std::cout << "s = " << std::dec << s << '\n'; 
    std::cout << "Era (expected: -1) = " << std::dec << era << '\n'; 
    std::cout << "Timestamp (expected: 4294880896) = " << std::dec << timestamp 
      << '\n'; 
    std::cout << "Fraction (expected: 123000) = " << std::dec << fraction << '\n'; 
}