C++ 将NTP时间转换为人类可读的时间

C++ 将NTP时间转换为人类可读的时间,c++,linux,protocols,ntp,C++,Linux,Protocols,Ntp,我已经设法发出了一个NTP请求,并从它的NTP响应中检索服务器时间。 我想把这个数字转换成一个人类可读的时间,用C++编写。 有人能帮我吗? 例如,您可以查看: 一旦您将时间戳设置为771554255,您将得到“29/7/2010 13:14:32”。 我想在我的代码中也这么做, 有什么帮助吗?< /P> < P>这不是C++,但这里是Perl实现。把这个转换成C++应该没什么大不了的: #用法:perl n2u.pl时间戳 #时间戳为十进制:[0-9]+.?[0-9]* #或十六进制:(0x

我已经设法发出了一个NTP请求,并从它的NTP响应中检索服务器时间。 我想把这个数字转换成一个人类可读的时间,用C++编写。 有人能帮我吗? 例如,您可以查看: 一旦您将时间戳设置为771554255,您将得到“29/7/2010 13:14:32”。 我想在我的代码中也这么做,
有什么帮助吗?< /P> < P>这不是C++,但这里是Perl实现。把这个转换成C++应该没什么大不了的:

#用法:perl n2u.pl时间戳
#时间戳为十进制:[0-9]+.?[0-9]*
#或十六进制:(0x)?[0-9]+。?(0x)?[0-9]*
#1900-01-01和1970-01-01之间的秒数
我的$NTP2UNIX=(70*365+17)*86400;
我的$timestamp=shift;
die“用法perl n2u.pl时间戳(带或不带小数)\n”
除非($timestamp ne“”);
my($i,$f)=拆分(/\./,$timestamp,2);
$f | |=0;
如果($i=~/^0x/){
$i=10月($i);
$f=($f=~/^0x/)?10月($f)/2**32:“0.$f”;
}否则{
$i=int($i);
$f=$timestamp-$i;
}
my$t=$i-$NTP2UNIX;
而($t<0){
$t+=65536.0*65536.0;
}
我的($year,$mon,$day,$h,$m,$s)=(gmtime($t))[5,4,3,2,1,0];
$s+=$f;
printf(“%d-%02d-%02d%02d:%02d:%06.3f\n”,
$year+1900、$mon+1、$day、$h、$m、$s);

<代码> > p>这是C++代码。但事实并非如此。。这里使用的windows api实现了所需的功能,但其背后有一个伟大的数学计算。。理解起来很痛苦,所以我没有把它放在这里。对于“CSNTPClient”类,您必须从URL.htm>http://read.pudn.com/downloads160/sourcecode/windows/comm/720007/SntpTest/Sntp.h_.htm“.这是PJ Notters代码示例的修改版本..你看…干杯

#include "stdafx.h"
int main()
{
    //Initialise the winsock stack
    WSADATA wsaData;
    BYTE wsMajorVersion = 1;
    BYTE wsMinorVersion = 1;
    WORD wVersionRequested = MAKEWORD(wsMinorVersion, wsMajorVersion);   
    if (WSAStartup(wVersionRequested, &wsaData) != 0) 
    {
        _tprintf(_T("Failed to load winsock stack\n"));
        return 1;
    }
    if (LOBYTE(wsaData.wVersion) != wsMajorVersion || HIBYTE(wsaData.wVersion) != wsMinorVersion)
    {
        _tprintf(_T("Winsock stack does not support version which this program requires\n"));
        WSACleanup();
        return 1;
    }

    //Do the actual NTP Query
    CSNTPClient sntp;
    NtpServerResponse response;
    if (sntp.GetServerTime(specify ntp server url or ip, response))
    {
        _tprintf(_T("Time was successfully retreived from NTP server\n"));

        SYSTEMTIME st1 = response.m_OriginateTime;
        SYSTEMTIME st2 = response.m_ReceiveTime;
        SYSTEMTIME st3 = response.m_TransmitTime;
        SYSTEMTIME st4 = response.m_DestinationTime;

        cout << response.m_DestinationTime << endl;

        TIME_ZONE_INFORMATION lpTimeZoneInfo;
        GetTimeZoneInformation(&lpTimeZoneInfo); //Get the local TIME ZONE
        SYSTEMTIME stLocal;
        //To Get Local Time from the fetched GMT/UTC Time from the server, use SystemTimeToTzSpecificLocalTime()
        //To get GMT/UTC Time from Local Time, use the API TzSpecificLocalTimeToSystemTime()
        SystemTimeToTzSpecificLocalTime(&lpTimeZoneInfo, &st3, &stLocal); 

        _tprintf(_T("\n"));
        _tprintf(_T("                            DD/MM/YYYY  HH:MM:SS.MS\n"));
        _tprintf(_T("\n\n\nObtaining Time thru API SystemTimeToTzSpecificLocalTime :\n\n"));
        _tprintf(_T("Server Transmit Date was    %02d/%02d/%04d, %02d:%02d:%02d.%03d\n"), st3.wDay, st3.wMonth, st3.wYear, st3.wHour, st3.wMinute, st3.wSecond, st3.wMilliseconds);
        _tprintf(_T("Client Destination Date was %02d/%02d/%04d, %02d:%02d:%02d.%03d\n"), stLocal.wDay, stLocal.wMonth, stLocal.wYear, stLocal.wHour, stLocal.wMinute, stLocal.wSecond, stLocal.wMilliseconds);
    }
}
#包括“stdafx.h”
int main()
{
//初始化winsock堆栈
WSADATA WSADATA;
字节wsMajorVersion=1;
字节wsMinorVersion=1;
WORD wVersionRequested=MAKEWORD(wsMinorVersion,wsMajorVersion);
如果(WSAStartup(wVersionRequested,&wsaData)!=0)
{
_tprintf(_T(“加载winsock堆栈失败”);
返回1;
}
如果(LOBYTE(wsaData.wVersion)!=wsMajorVersion | | HIBYTE(wsaData.wVersion)!=wsMinorVersion)
{
_tprintf(_T(“Winsock堆栈不支持此程序所需的版本”);
WSACleanup();
返回1;
}
//执行实际的NTP查询
CSNTP客户sntp;
ntpserver响应;
if(sntp.GetServerTime(指定ntp服务器url或ip,响应))
{
_tprintf(_T(“从NTP服务器成功检索时间”);
SYSTEMTIME st1=响应时间m_初始时间;
SYSTEMTIME st2=响应时间m\u接收时间;
SYSTEMTIME st3=响应时间m_传输时间;
SYSTEMTIME st4=response.m_DestinationTime;

cout这是我对这个问题的解决方案。它是公认答案中提到的PERL代码的简化副本

void unix_to_ntp(uint32_t& timestamp) {
    /**
     * Unix uses an epoch located at 1.1.1970 - 00:00h (UTC)
     * and NTP uses 1.1.1900 - 00:00h (UTC) which leads to an
     * offset equivalent to 70 years in seconds (note that
     * there are 17 leap years between the two dates)
     */
    constexpr uint8_t  NTP_UNIX_OFFSET_YEARS = 70;
    constexpr uint16_t DAYS_IN_YEAR          = 365;
    constexpr uint8_t  NUMBER_OF_LEAP_YEARS  = 17;
    constexpr uint32_t SECONDS_IN_DAY        = 86400;
    constexpr uint32_t NTP_UNIX_OFFSET_SECONDS =
        (NTP_UNIX_OFFSET_YEARS * DAYS_IN_YEAR + NUMBER_OF_LEAP_YEARS) * SECONDS_IN_DAY;

    timestamp = timestamp - NTP_UNIX_OFFSET_SECONDS;
}

uint32_t unix_to_ntp(uint32_t const& timestamp) {
    uint32_t tmp = timestamp;
    unix_to_ntp(tmp);
    return tmp;
}

std::string timestamp_to_str(uint32_t const& timestamp) {
    struct tm *t;
    char buffer[20];
    long int tmp = timestamp;
    t = gmtime(&tmp);
    strftime(buffer, sizeof(buffer), "%F %T", t);
    return std::string(buffer);
}
那么就这样使用它:

timestamp_to_str(unix_to_ntp(...));

正如第一个答案所提到的,您所指的页面不处理NTP时间戳(64位,秒+秒分数,从1900年1月1日起),而是处理Unix时间(32位,从1970年1月1日起秒)。您想要哪一个?作为一个短命(?)答案(使用Perl示例),只需取前32位,去掉1900年1月1日到1970年1月1日之间的秒数(大约70*365.25*24*3600),就可以使用Unix时间()兼容的值……只是为了检查,在NTP时间戳中给出了秒数的32位,从1968开始就有高阶位…所以,作为有符号整数,它看起来是负的。我最初对此发布时犹豫了一下,因为它是Perl,不是C++。但是方法是正确的,并且可以很容易地移植到C++。20世纪80年代的ime?嘿,我认为一个独立的解决方案及其描述会更好。
timestamp_to_str(unix_to_ntp(...));