Windows 11 C++设置系统时间
在Windows 11中,使用C++设置系统时间需要管理员权限。设置系统时间涉及修改操作系统的关键参数,为了防止未经授权的修改,Windows要求进行这些操作的用户拥有管理员权限。
在C++中,设置系统时间可以通过调用Windows API函数SetSystemTime
来实现。然而,在调用这个函数之前,必须确保程序以管理员身份运行,否则会失败并返回权限不足的错误。
示例代码
以下是一个使用SetSystemTime
函数设置系统时间的简单示例:
#include <windows.h>
#include <iostream>
int main() {
// 创建一个SYSTEMTIME结构体,并设置时间
SYSTEMTIME st;
st.wYear = 2024;
st.wMonth = 6;
st.wDay = 4;
st.wHour = 12;
st.wMinute = 0;
st.wSecond = 0;
st.wMilliseconds = 0;
// 设置系统时间
if (SetSystemTime(&st)) {
std::cout << "系统时间设置成功。" << std::endl;
} else {
std::cout << "系统时间设置失败。" << std::endl;
}
return 0;
}
提升权限
为了以管理员身份运行程序,可以在程序的属性中设置,也可以在代码中检查并请求管理员权限。以下是一个简单的实现方法,通过创建一个新的进程以管理员权限重新运行自己:
#include <windows.h>
#include <shellapi.h>
#include <iostream>
bool IsRunAsAdministrator() {
BOOL isElevated = FALSE;
HANDLE token = nullptr;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
TOKEN_ELEVATION elevation;
DWORD size;
if (GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &size)) {
isElevated = elevation.TokenIsElevated;
}
CloseHandle(token);
}
return isElevated;
}
void ElevateToAdministrator() {
char path[MAX_PATH];
GetModuleFileName(NULL, path, ARRAYSIZE(path));
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.lpVerb = "runas";
sei.lpFile = path;
sei.hwnd = NULL;
sei.nShow = SW_NORMAL;
if (!ShellExecuteEx(&sei)) {
DWORD dwError = GetLastError();
if (dwError == ERROR_CANCELLED) {
std::cerr << "用户取消了提升操作。" << std::endl;
}
}
}
int main() {
if (!IsRunAsAdministrator()) {
std::cout << "程序未以管理员身份运行。尝试提升权限..." << std::endl;
ElevateToAdministrator();
return 0;
}
SYSTEMTIME st;
st.wYear = 2024;
st.wMonth = 6;
st.wDay = 4;
st.wHour = 12;
st.wMinute = 0;
st.wSecond = 0;
st.wMilliseconds = 0;
if (SetSystemTime(&st)) {
std::cout << "系统时间设置成功。" << std::endl;
} else {
std::cout << "系统时间设置失败。" << std::endl;
}
return 0;
}
这个示例代码首先检查程序是否以管理员身份运行。如果不是,则尝试重新启动自己并请求管理员权限。如果用户接受了权限提升请求,程序将以管理员身份重新启动,并设置系统时间。
C++设置系统时间的几种方式
在Windows 11上,用C++代码设置系统时间可以通过多种方式实现。下面是一些常见的方法:
- 使用
SetLocalTime
API: - 使用
SetSystemTime
API: - 调用命令行工具
w32tm
: - 调用命令行工具
date
和time
:
每种方法的具体实现如下:
方法 1: 使用 SetLocalTime
API
SetLocalTime
设置本地时间(即系统时区下的时间)。
#include <iostream>
#include <windows.h>
bool SetLocalSystemTime(int year, int month, int day, int hour, int minute, int second) {
// Initialize SYSTEMTIME structure
SYSTEMTIME st;
GetLocalTime(&st); // Get current local time
st.wYear = year;
st.wMonth = month;
st.wDay = day;
st.wHour = hour;
st.wMinute = minute;
st.wSecond = second;
st.wMilliseconds = 0; // Optional: can be set to 0
// Set the new local system time
if (!SetLocalTime(&st)) {
std::cerr << "Failed to set local system time. Error: " << GetLastError() << std::endl;
return false;
}
return true;
}
int main() {
int year = 2024;
int month = 6;
int day = 4;
int hour = 12;
int minute = 30;
int second = 0;
if (SetLocalSystemTime(year, month, day, hour, minute, second)) {
std::cout << "Local system time set successfully." << std::endl;
} else {
std::cerr << "Failed to set local system time." << std::endl;
}
return 0;
}
方法 2: 使用 SetSystemTime
API
SetSystemTime
设置UTC时间(协调世界时),在大多数情况下需要转换为本地时间后使用。
#include <iostream>
#include <windows.h>
bool SetSystemTimeUTC(int year, int month, int day, int hour, int minute, int second) {
// Initialize SYSTEMTIME structure
SYSTEMTIME st;
GetSystemTime(&st); // Get current system time
st.wYear = year;
st.wMonth = month;
st.wDay = day;
st.wHour = hour;
st.wMinute = minute;
st.wSecond = second;
st.wMilliseconds = 0; // Optional: can be set to 0
// Set the new system time (UTC)
if (!SetSystemTime(&st)) {
std::cerr << "Failed to set system time (UTC). Error: " << GetLastError() << std::endl;
return false;
}
return true;
}
int main() {
int year = 2024;
int month = 6;
int day = 4;
int hour = 12;
int minute = 30;
int second = 0;
if (SetSystemTimeUTC(year, month, day, hour, minute, second)) {
std::cout << "System time (UTC) set successfully." << std::endl;
} else {
std::cerr << "Failed to set system time (UTC)." << std::endl;
}
return 0;
}
方法 3: 调用命令行工具 w32tm
使用C++代码调用系统命令行工具 w32tm
来设置时间。
#include <iostream>
#include <cstdlib> // for system()
bool SyncSystemTimeWithW32tm() {
// Construct the command to sync system time using w32tm
const char* command = "w32tm /resync";
// Execute the command
int result = system(command);
if (result != 0) {
std::cerr << "Failed to sync system time using w32tm. Error code: " << result << std::endl;
return false;
}
return true;
}
int main() {
if (SyncSystemTimeWithW32tm()) {
std::cout << "System time synced successfully using w32tm." << std::endl;
} else {
std::cerr << "Failed to sync system time using w32tm." << std::endl;
}
return 0;
}
方法 4: 调用命令行工具 date
和 time
使用C++代码调用 date
和 time
命令来设置系统日期和时间。
#include <iostream>
#include <cstdlib> // for system()
bool SetSystemDateAndTime(const std::string& date, const std::string& time) {
// Construct the command to set the date
std::string dateCommand = "date " + date;
std::string timeCommand = "time " + time;
// Execute the date command
int resultDate = system(dateCommand.c_str());
if (resultDate != 0) {
std::cerr << "Failed to set system date. Error code: " << resultDate << std::endl;
return false;
}
// Execute the time command
int resultTime = system(timeCommand.c_str());
if (resultTime != 0) {
std::cerr << "Failed to set system time. Error code: " << resultTime << std::endl;
return false;
}
return true;
}
int main() {
std::string date = "06-04-24"; // MM-DD-YY format
std::string time = "12:30:00"; // HH:MM:SS format
if (SetSystemDateAndTime(date, time)) {
std::cout << "System date and time set successfully." << std::endl;
} else {
std::cerr << "Failed to set system date and time." << std::endl;
}
return 0;
}
注意事项
- 权限:更改系统时间需要管理员权限。确保运行这些程序时使用管理员权限。
- 时区:
SetLocalTime
和SetSystemTime
的主要区别是时区。使用SetSystemTime
时,你需要处理UTC时间。 - 安全:更改系统时间可能会影响系统的其他服务和功能,请谨慎使用。
通过以上方法,你可以在Windows 11上使用C++代码设置系统时间。选择最适合你需求的方法来实现。
时区 本地时间+8
要将 SYSTEMTIME
结构中的时间增加8小时(例如,从UTC时间转换为中国标准时间(CST)),可以使用以下步骤:
- 将
SYSTEMTIME
转换为FILETIME
。 - 使用
ULARGE_INTEGER
结构增加8小时的时间。 - 将
FILETIME
转换回SYSTEMTIME
。
下面是具体的实现代码:
#include <iostream>
#include <windows.h>
void AddHoursToSystemTime(SYSTEMTIME& st, int hours) {
// Convert SYSTEMTIME to FILETIME
FILETIME ft;
SystemTimeToFileTime(&st, &ft);
// Convert FILETIME to ULARGE_INTEGER
ULARGE_INTEGER li;
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
// Add hours (converted to 100-nanosecond intervals)
li.QuadPart += static_cast<ULONGLONG>(hours) * 60 * 60 * 10000000;
// Convert back to FILETIME
ft.dwLowDateTime = li.LowPart;
ft.dwHighDateTime = li.HighPart;
// Convert FILETIME back to SYSTEMTIME
FileTimeToSystemTime(&ft, &st);
}
int main() {
// Initialize SYSTEMTIME with some UTC time
SYSTEMTIME st;
st.wYear = 2024;
st.wMonth = 6;
st.wDay = 4;
st.wHour = 12;
st.wMinute = 30;
st.wSecond = 0;
st.wMilliseconds = 0;
std::cout << "Original UTC time: "
<< st.wYear << "-" << st.wMonth << "-" << st.wDay << " "
<< st.wHour << ":" << st.wMinute << ":" << st.wSecond << std::endl;
// Add 8 hours to convert to local time
AddHoursToSystemTime(st, 8);
std::cout << "Local time (UTC+8): "
<< st.wYear << "-" << st.wMonth << "-" << st.wDay << " "
<< st.wHour << ":" << st.wMinute << ":" << st.wSecond << std::endl;
return 0;
}
解释
- SYSTEMTIME到FILETIME的转换:使用
SystemTimeToFileTime
函数将SYSTEMTIME
转换为FILETIME
。 - FILETIME到ULARGE_INTEGER的转换:因为
FILETIME
由两个32位值组成,使用ULARGE_INTEGER
可以方便地进行加法操作。 - 添加小时数:将小时数转换为100纳秒的间隔进行加法操作。1小时=3600秒,1秒=10000000个100纳秒单位。
- 转换回SYSTEMTIME:将修改后的
FILETIME
转换回SYSTEMTIME
。
通过这种方式,你可以将 SYSTEMTIME
结构中的时间增加8小时,转换为本地时间(如UTC+8的中国标准时间)。
同步时间
从服务器获取时间 TCP连接后会自动收到4字节,倒序即为时间戳,自动断开TCP。如果不稳定,就多找几个ip轮循。
比如: TCP 128.138.141.172:37 科罗拉多大学博尔德分校 美国 科罗拉多州 博尔德
使用
if (GetPrivateProfileInt("CFG_FILE", "EnableSyncPCTime", YES, configFileName))//同步PC时间
{
logger.INFO_F("查询当前是否以管理员运行");
if (!IsRunAsAdministrator()) {
logger.INFO_F("程序未以管理员身份运行。尝试提升权限...");
ElevateToAdministrator();
logger.Close();
exit(0);
}
else { logger.INFO_F("当前为管理员运行模式"); }
pWnd->ShowInfo("开始同步PC时间,请等待");
Sleep(100);
while(TRUE)
{
if (DEF_SYNDATETIME_SUCCESS == SYNServerDateTime())
{
SYSTEMTIME st;
CHAR temp[64] = { 0 };
GetLocalTime(&st);
//sprintf(temp, "2000010203040506"); //test
sprintf(temp, "%04d年%02d月%02d日 %02d时%02d分%02d秒", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
pWnd->ShowInfo("同步PC时间:PASS "+CString(temp));
break;
}
else
{
AfxMessageBox("同步PC时间:FAIL "+CString(logger.errMessage.c_str()) + " 点OK重试");
}
}
}
else { logger.INFO_F("同步PC时间:关"); }
#include "ServerDateTime.h"
#include "winsock2.h"
#pragma comment(lib, "WS2_32.lib") // 显式连接套接字库
#include"utility.h"
#include "./pch.h"
#define TIME_SERVER_IP "128.138.141.172"
static WORD g_SYNDateTime = DEF_SYNDATETIME_ERROR;
SYSTEMTIME FormatServerTime(DWORD serverTime);
DWORD GetTimeFromServer(char *ip_addr);
void AddHoursToSystemTime(SYSTEMTIME& st, int hours) {
// Convert SYSTEMTIME to FILETIME
FILETIME ft;
SystemTimeToFileTime(&st, &ft);
// Convert FILETIME to ULARGE_INTEGER
ULARGE_INTEGER li;
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
// Add hours (converted to 100-nanosecond intervals)
li.QuadPart += static_cast<ULONGLONG>(hours) * 60 * 60 * 10000000;
// Convert back to FILETIME
ft.dwLowDateTime = li.LowPart;
ft.dwHighDateTime = li.HighPart;
// Convert FILETIME back to SYSTEMTIME
FileTimeToSystemTime(&ft, &st);
}
WORD SYNServerDateTime2()
{
DWORD dwTime = 0;
SYSTEMTIME st;
dwTime = GetTimeFromServer(TIME_SERVER_IP);
if (dwTime == 0)
{
g_SYNDateTime = DEF_SYNDATETIME_ERROR;
return g_SYNDateTime;
}
st = FormatServerTime(dwTime);
// 校时 本机
if (SetSystemTime(&st))
{
printf("SetSystemTime set successfully.\n");
}
else {
g_SYNDateTime = DEF_SYNDATETIME_ERROR;
printf("Failed to set SetSystemTime. 必须以管理员方式运行\n");
return g_SYNDateTime;
}
CString m_Time;
m_Time.Format(_T("格林尼治时间为:%d年%d月%d日%d时%d分%d秒%d\n"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
printf(m_Time);
AddHoursToSystemTime(st, 8);
//if (SetLocalTime(&st)) // 用这个差八小时
//{
// printf("SetLocalTime set successfully.\n");
//}
//else {
// printf("Failed to set SetLocalTime.\n");
//}
m_Time.Format(_T("北京时间为:%d年%d月%d日%d时%d分%d秒%d\n"), st.wYear, st.wMonth, st.wDay, st.wHour , st.wMinute, st.wSecond, st.wMilliseconds);
printf(m_Time);
g_SYNDateTime = DEF_SYNDATETIME_SUCCESS;
return g_SYNDateTime;
}
WORD SYNServerDateTime()
{
for(int i=0;i<10;i++)
{
if (SYNServerDateTime2() == DEF_SYNDATETIME_SUCCESS) { return g_SYNDateTime; }
Sleep(10);
}
return g_SYNDateTime;
}
WORD GetDateAndTime(BYTE *pbDate, BYTE *pbTime)
{
CString m_strDate;
CString m_strTime;
CString m_strDateTime;
BYTE pbTmp[32];
if (g_SYNDateTime== DEF_SYNDATETIME_SUCCESS)
{
CTime m_time;
m_time = CTime::GetCurrentTime(); //获取当前时间日期
//m_strDate = m_time.Format("%x"); //格式化日期
//m_strTime = m_time.Format("%X"); //格式化时间
//m_strDateTime = m_time.Format("%Y-%m-%d %H:%M:%S %A"); //格式化日期时间
m_strDate = m_time.Format("%Y%m%d");
m_strTime = m_time.Format("%H%M%S");
memset(pbTmp, 0x00, sizeof(pbTmp));
sprintf((char *)pbTmp, "%s", m_strDate);
StrToHex(pbDate, (char*)pbTmp, strlen((char *)pbTmp)/2);
memset(pbTmp, 0x00, sizeof(pbTmp));
sprintf((char *)pbTmp, "%s", m_strTime);
StrToHex(pbTime, (char*)pbTmp, strlen((char *)pbTmp)/2);
}
return g_SYNDateTime;
}
//从服务器获取时间 返回0错误
DWORD GetTimeFromServer(char *ip_addr)
{
// 参数ip_addr:表示指定的时间服务器IP地址
// 返回:自1900年1月1日午0时0分0秒至今的毫秒数 或 0(表示获取失败)
// 默认的时间服务器为"国家授时中心"
if (ip_addr == NULL)
{
ip_addr = _T(TIME_SERVER_IP);
}
// 定义WSADATA结构体对象
WSADATA date;
// 定义版本号码
WORD w = MAKEWORD(2, 0);
// 初始化套接字库
if (::WSAStartup(w, &date) != 0)
{
logger.ERROR_F("初始化套接字库失败!");
return 0;
}
// 定义连接套接字句柄
SOCKET s;
// 定义接收信息保存变量
DWORD m_serverTime;
// 创建TCP套接字
s = ::socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == s)
{
logger.ERROR_F("创建套接字失败!");
// 关闭套接字句柄
::closesocket(s);
// 释放套接字库
::WSACleanup();
return 0;
}
// 定义套接字地址结构
sockaddr_in addr;
// 初始化地址结构
addr.sin_family = AF_INET;
addr.sin_port = htons(37);
addr.sin_addr.S_un.S_addr = inet_addr(ip_addr);
// 连接
if (::connect(s, (sockaddr*)&addr, sizeof(addr)) != 0)
{
int errorCode = ::WSAGetLastError();
switch (errorCode)
{
case 10060:
logger.ERROR_F("连接超时! " + to_string(errorCode));
break;
case 10051:
case 10065:
logger.ERROR_F("网络不可达! " + to_string(errorCode));
break;
default:
logger.ERROR_F("WSAGetLastError(): "+to_string(errorCode));
}
// 关闭套接字句柄
::closesocket(s);
// 释放套接字库
::WSACleanup();
return 0;
}
// 接收
if (::recv(s, (char *)&m_serverTime, 4, MSG_PEEK) <= 0)
{
logger.ERROR_F("接收错误!WSAGetLastError(): "+to_string( ::WSAGetLastError()));
// 关闭套接字句柄
::closesocket(s);
// 释放套接字库
::WSACleanup();
return 0;
}
// 关闭套接字句柄
::closesocket(s);
// 释放套接字库
::WSACleanup();
logger.INFO_F("获取服务器时间成功!" + bytesToHexString((BYTE*)&m_serverTime, 4));
// 网络字节顺序转换为主机字节顺序 倒过来
m_serverTime = ::ntohl(m_serverTime);
// 返回接收到的数据
return m_serverTime;
}
//格式化时间
SYSTEMTIME FormatServerTime(DWORD serverTime)
{
FILETIME ftNew;
SYSTEMTIME stNew;
stNew.wYear = 1900;
stNew.wMonth = 1;
stNew.wDay = 1;
stNew.wHour = 0;
stNew.wMinute = 0;
stNew.wSecond = 0;
stNew.wMilliseconds = 0;
::SystemTimeToFileTime(&stNew, &ftNew);
/* 将SYSTEMTIME结构设定为1900年1月1日午夜(0时)。
并将这个SYSTEMTIME结构传递给SystemTimeToFileTime,将此结构转化为FILETIME结构。
FILETIME实际上只是由两个32位元的DWORD一起组成64位元的整数,
用来表示从1601年1月1日至今间隔为100奈秒(nanosecond)的间隔数。 */
LARGE_INTEGER li; //64位大整数
li = *(LARGE_INTEGER *)&ftNew;
li.QuadPart += (LONGLONG)10000000 * serverTime;
ftNew = *(FILETIME *)&li;
::FileTimeToSystemTime(&ftNew, &stNew);
// 返回时间(注意:这里返回的是格林尼治时间,与北京时间相差8小时)
return stNew;
}
头文件
#ifndef _SERVER_DATE_TIME_H_
#define _SERVER_DATE_TIME_H_
#include <afx.h>
#define DEF_SYNDATETIME_SUCCESS (1)
#define DEF_SYNDATETIME_ERROR (0)
//1、同步服务器时间到本机PC
WORD SYNServerDateTime();
//1操作是否成功
//WORD GetSynDateTimeStatus();
//2、如果1成功,从本机获取时间
WORD GetDateAndTime(BYTE *pbDate,BYTE *pbTime);
#endif /**/
设置时间测试示例
#include <iostream>
#include <windows.h>
#include <iostream>
#include <windows.h>
void AddHoursToSystemTime(SYSTEMTIME& st, int hours) {
// Convert SYSTEMTIME to FILETIME
FILETIME ft;
SystemTimeToFileTime(&st, &ft);
// Convert FILETIME to ULARGE_INTEGER
ULARGE_INTEGER li;
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
// Add hours (converted to 100-nanosecond intervals)
li.QuadPart += static_cast<ULONGLONG>(hours) * 60 * 60 * 10000000;
// Convert back to FILETIME
ft.dwLowDateTime = li.LowPart;
ft.dwHighDateTime = li.HighPart;
// Convert FILETIME back to SYSTEMTIME
FileTimeToSystemTime(&ft, &st);
}
bool SetSystemTime(int year, int month, int day, int hour, int minute, int second) {
// Initialize SYSTEMTIME structure
SYSTEMTIME st;
GetSystemTime(&st); // Get current system time
st.wYear = year;
st.wMonth = month;
st.wDay = day;
st.wHour = hour;
st.wMinute = minute;
st.wSecond = second;
st.wMilliseconds = 0; // Optional: can be set to 0
// Set the new system time
if (!SetSystemTime(&st)) {
std::cerr << "Failed to set system time. Error: " << GetLastError() << std::endl;
return false;
}
return true;
}
bool SetLocalSystemTime(int year, int month, int day, int hour, int minute, int second) {
// Initialize SYSTEMTIME structure
SYSTEMTIME st;
GetLocalTime(&st); // Get current local time
st.wYear = year;
st.wMonth = month;
st.wDay = day;
st.wHour = hour;
st.wMinute = minute;
st.wSecond = second;
st.wMilliseconds = 0; // Optional: can be set to 0
// Set the new local system time
if (!SetLocalTime(&st)) {
std::cerr << "Failed to set local system time. Error: " << GetLastError() << std::endl;
return false;
}
return true;
}
int main() {
int year = 2011;
int month = 11;
int day = 11;
int hour = 11;
int minute = 11;
int second = 11;
if (SetLocalSystemTime(year, month, day, hour, minute, second)) {
std::cout << "Local system time set successfully." << std::endl;
}
else {
std::cerr << "Failed to set local system time." << std::endl;
}
std::cin;
getchar();
SYSTEMTIME st;
st.wYear = 2012;
st.wMonth = 12;
st.wDay = 12;
st.wHour = 12;
st.wMinute = 12;
st.wSecond = 12;
st.wMilliseconds = 0;
AddHoursToSystemTime(st, -8);
if (SetSystemTime(st.wYear,st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond)) {
std::cout << "SetSystemTime set successfully." << std::endl;
}
else {
std::cerr << "Failed to set SetSystemTime." << std::endl;
}
std::cin;
getchar();
return 0;
}