本文示範如何使用 Python 連線 NTP 時間伺服器(國家授時中心),解析回傳時間封包,並透過 win32api.SetSystemTime 修改 Windows 系統時間。適用於離線環境、嵌入式裝置、自動化測試需精確校時的場景。
0x1b + 47 bytes 零填充)time.gmtime 結構win32api.SetSystemTime 寫入系統時間
# -*- coding: utf-8 -*-
import socket
import struct
import time
import win32api
# 國家授時中心 IP(可替換為 pool.ntp.org 等)
TIME_SERVER = '210.72.145.44'
PORT = 123
NTP_EPOCH_OFFSET = 2208988800 # 1900-01-01 到 1970-01-01 的秒數
def get_ntp_time():
"""從 NTP 伺服器取得 Unix timestamp"""
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client.settimeout(5)
# NTP 請求封包:LI=0, VN=3, Mode=3 (Client) = 0x1b
data = b'\x1b' + b'\x00' * 47
client.sendto(data, (TIME_SERVER, PORT))
data, _ = client.recvfrom(1024)
client.close()
# 解析:第 10 個 32-bit 無號整數為 Transmit Timestamp
transmit_ts = struct.unpack('!12I', data)[10]
unix_ts = transmit_ts - NTP_EPOCH_OFFSET
return unix_ts
def set_system_time():
"""設定 Windows 系統時間"""
ntp_time = get_ntp_time()
# gmtime 回傳 struct_time: (年, 月, 日, 時, 分, 秒, 週幾, 年天數, 夏令時)
tm = time.gmtime(ntp_time)
# win32api.SetSystemTime(year, month, dayOfWeek, day, hour, minute, second, milliseconds)
# 注意:dayOfWeek 為 0=星期日,time.gmtime 回傳 0=星期一,需轉換
day_of_week = (tm.tm_wday + 1) % 7 # Python: 0=Mon → Windows: 0=Sun
win32api.SetSystemTime(
tm.tm_year, tm.tm_mon, day_of_week, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, 0
)
print("系統時間同步完成!")
if __name__ == '__main__':
set_system_time()
# 驗證
ntp_time = get_ntp_time()
local = time.localtime(ntp_time)
print("當前系統時間: %04d-%02d-%02d %02d:%02d:%02d" % local[:6])
| 項目 | 說明 |
|---|---|
| NTP 封包格式 | RFC 5905 定義,前 48 bytes 為標準頭部 |
| struct.unpack('!12I') | 網路序 (big-endian) 解析 12 個 unsigned int |
| 索引 [10] | 第 11 個欄位為 Transmit Timestamp(伺服器發送時間) |
| 紀元差異 | NTP 以 1900 為紀元,Unix 以 1970,差 2208988800 秒 |
| weekday 轉換 | Python tm_wday: 0=Mon;Windows: 0=Sun,需 (wday+1)%7 |
| 權限需求 | 修改系統時間需管理員權限執行 |
os.system('date -s @"%d"' % ts) 或 ctypes 呼叫 clock_settimentplib 封裝 NTP 協定,python-ntp 提供更高階介面time.windows.com、pool.ntp.org)pywin32:pip install pywin32SetSystemTime 亦為 UTC,系統會依時區自動換算顯示