2019-08-02-C++控制台获取UTC和北京时间

2019-08-02-C++控制台获取UTC和北京时间

代码来源 https://www.2cto.com/kf/201209/152988.html

image.png

如果IP不可用,参考https://tf.nist.gov/tf-cgi/servers.cgi

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// CSTget.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <winsock2.h>
#include <iostream>
#pragma comment(lib, "WS2_32") // 链接到WS2_32.lib
//using std;

class CInitSock
{
public:
CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)
{
// 初始化WS2_32.dll
WSADATA wsaData;
WORD sockVersion = MAKEWORD(minorVer, majorVer);
if (::WSAStartup(sockVersion, &wsaData) != 0)
{
exit(0);
}
}
~CInitSock()
{
::WSACleanup();
}
};


//#include "InitSock.h"
#include <stdio.h>
CInitSock initSock;

void SetTimeFromTP(ULONG ulTime) // 根据时间协议返回的时间设置系统时间
{
// Windows文件时间是一个64位的值,它是从1601年1月1日中午12:00到现在的时间间隔,
// 单位是1/1000 0000秒,即1000万分之1秒(100-nanosecond )
FILETIME ft;
SYSTEMTIME st;

// 首先将基准时间(1900年1月1日0点0分0秒0毫秒)转化为Windows文件时间
st.wYear = 1900;
st.wMonth = 1;
st.wDay = 1;
st.wHour = 0;
st.wMinute = 0;
st.wSecond = 0;
st.wMilliseconds = 0;
SystemTimeToFileTime(&st, &ft);

// 然后将Time Protocol使用的基准时间加上以及逝去的时间,即ulTime
LONGLONG *pLLong = (LONGLONG *)&ft;
// 注意,文件时间单位是1/1000 0000秒,即1000万分之1秒(100-nanosecond )
*pLLong += (LONGLONG)10000000 * ulTime;

// 再将时间转化回来,更新系统时间
FileTimeToSystemTime(&ft, &st);

std::cout << "UTC "<<st.wYear <<"年"<< st.wMonth << "月" << st.wDay<<"日" << st.wHour << "时" <<st.wMinute << "分" << st.wSecond << "秒\n";
std::cout << "北京时间 " << st.wYear << "年" << st.wMonth << "月" << st.wDay+ (st.wHour + 8) / 24 << "日" << (st.wHour + 8)%24 << "时" << st.wMinute << "分" << st.wSecond << "秒\n";
std::cout << "美东时间 " << st.wYear << "年" << st.wMonth << "月" << st.wDay - (st.wHour < 8 ? 1: 0 ) << "日" << (st.wHour - 8 +24) % 24 << "时" << st.wMinute << "分" << st.wSecond << "秒\n";


SetSystemTime(&st);
}

int main()
{
SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
printf(" Failed socket() \n");
return 0;
}

// 填写远程地址信息,连接到时间服务器
sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(37);
// 这里使用的时间服务器是129.132.2.21,更多地址请参考谷歌 https://tf.nist.gov/tf-cgi/servers.cgi ntp time server ip
servAddr.sin_addr.S_un.S_addr = inet_addr("132.163.97.5");
if (::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)
{
printf(" Failed connect() \n");
return 0;
}

// 等待接收时间协议返回的时间。学习了Winsock I/O模型之后,最好使用异步I/O,以便设置超时
ULONG ulTime = 0;
int nRecv = ::recv(s, (char*)&ulTime, sizeof(ulTime), 0);
if (nRecv > 0)
{
ulTime = ntohl(ulTime);
SetTimeFromTP(ulTime);
//printf(" 成功与时间服务器的时间同步!\n");
//std::cout << ulTime<<"\n";
}
else
{
printf(" 时间服务器不能确定当前时间!\n");
}

::closesocket(s);
return 0;
}

改进版本:实时刷新但是不用占用网络资源,适合于短时间内动态查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

// WSTget.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <winsock2.h>
#include <iostream>
#pragma comment(lib, "WS2_32") // 链接到WS2_32.lib
//using std;
#include <time.h>
#include <windows.h>

class CInitSock
{
public:
CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)
{
// 初始化WS2_32.dll
WSADATA wsaData;
WORD sockVersion = MAKEWORD(minorVer, majorVer);
if (::WSAStartup(sockVersion, &wsaData) != 0)
{
exit(0);
}
}
~CInitSock()
{
::WSACleanup();
}
};


//#include "InitSock.h"
#include <stdio.h>
CInitSock initSock;


using namespace std;

void No_Cursor()
{
HANDLE hOut;
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 1;
cci.bVisible = false;
SetConsoleCursorInfo(hOut, &cci);
}

void gotoxy(short x, short y)
{
COORD pos = { x,y };
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut, pos);
No_Cursor();
}


void SetTimeFromTP(ULONG ulTime) // 根据时间协议返回的时间设置系统时间
{
// Windows文件时间是一个64位的值,它是从1601年1月1日中午12:00到现在的时间间隔,
// 单位是1/1000 0000秒,即1000万分之1秒(100-nanosecond )
FILETIME ft;
SYSTEMTIME st;

// 首先将基准时间(1900年1月1日0点0分0秒0毫秒)转化为Windows文件时间
st.wYear = 1900;
st.wMonth = 1;
st.wDay = 1;
st.wHour = 0;
st.wMinute = 0;
st.wSecond = 0;
st.wMilliseconds = 0;
SystemTimeToFileTime(&st, &ft);

// 然后将Time Protocol使用的基准时间加上以及逝去的时间,即ulTime
LONGLONG *pLLong = (LONGLONG *)&ft;
// 注意,文件时间单位是1/1000 0000秒,即1000万分之1秒(100-nanosecond )
*pLLong += (LONGLONG)10000000 * ulTime;

// 再将时间转化回来,更新系统时间
FileTimeToSystemTime(&ft, &st);


//std::cout << "UTC " << st.wYear << "Year" << st.wMonth << "Month" << st.wDay << "Day" << st.wHour << "Hour" << st.wMinute << "Minute" << st.wSecond << "Second\n";
//std::cout << "CST " << st.wYear << "Year" << st.wMonth << "Month" << st.wDay + (st.wHour + 8) / 24 << "Day" << (st.wHour + 8) % 24 << "Hour" << st.wMinute << "Minute" << st.wSecond << "Second\n";
//std::cout << "EST " << st.wYear << "Year" << st.wMonth << "Month" << st.wDay - (st.wHour < 8 ? 1 : 0) << "Day" << (st.wHour - 8 + 24) % 24 << "Hour" << st.wMinute << "Minute" << st.wSecond << "Second\n";

while (1)
{
gotoxy(0, 0);
std::cout << " \n \n \n";
gotoxy(0, 0);
std::cout << "CST " << st.wYear << "-" << st.wMonth << "-" << st.wDay + (st.wHour + 8) / 24 << " " << (st.wHour + 8) % 24 << ":" << st.wMinute << ":" << st.wSecond << "\n";
gotoxy(0, 1);
std::cout << "UTC " << st.wYear << "-" << st.wMonth << "-" << st.wDay << " " << st.wHour << ":" << st.wMinute << ":" << st.wSecond << "\n";
gotoxy(0, 2);
std::cout << "EST " << st.wYear << "-" << st.wMonth << "-" << st.wDay - (st.wHour < 8 ? 1 : 0) << " " << (st.wHour - 8 + 24) % 24 << ":" << st.wMinute << ":" << st.wSecond << "\n";

Sleep(1000);

st.wHour = st.wHour + (st.wMinute + 1) / 60;

st.wMinute = st.wMinute + (st.wSecond + 1) / 60; //59jump?

st.wSecond = (st.wSecond + 1) % 60;
}

//SetSystemTime(&st);
}

int func()
{
SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
printf(" Failed socket() \n");
return 0;
}

// 填写远程地址信息,连接到时间服务器
sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(37);
// 这里使用的时间服务器是129.132.2.21,更多地址请参考谷歌 https://tf.nist.gov/tf-cgi/servers.cgi ntp time server ip
servAddr.sin_addr.S_un.S_addr = inet_addr("132.163.97.5");
if (::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)
{
printf(" Failed connect() \n");
return 0;
}

// 等待接收时间协议返回的时间。学习了Winsock I/O模型之后,最好使用异步I/O,以便设置超时
ULONG ulTime = 0;
int nRecv = ::recv(s, (char*)&ulTime, sizeof(ulTime), 0);
if (nRecv > 0)
{
ulTime = ntohl(ulTime);
SetTimeFromTP(ulTime);
//printf(" 成功与时间服务器的时间同步!\n");
//std::cout << ulTime<<"\n";
}
else
{
printf(" 时间服务器不能确定当前时间!\n");
}

::closesocket(s);
return 0;
}

int main()
{
func();

}