time_sync.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. """
  2. 时间同步工具模块
  3. """
  4. import subprocess
  5. from utils.logger import logger
  6. import platform
  7. import time
  8. from typing import Optional
  9. class TimeSync:
  10. """时间同步类"""
  11. def __init__(self):
  12. self.ntp_servers = [
  13. "ntp.aliyun.com",
  14. "ntp1.aliyun.com",
  15. "ntp2.aliyun.com",
  16. "time.windows.com",
  17. "pool.ntp.org"
  18. ]
  19. def sync_time(self) -> bool:
  20. """
  21. 同步系统时间
  22. Returns:
  23. bool: 同步是否成功
  24. """
  25. try:
  26. logger.info("开始同步系统时间...")
  27. # 检测操作系统
  28. system = platform.system()
  29. if system == "Linux":
  30. return self._sync_linux()
  31. elif system == "Windows":
  32. return self._sync_windows()
  33. else:
  34. logger.warning(f"不支持的操作系统: {system}")
  35. return False
  36. except Exception as e:
  37. logger.error(f"时间同步失败: {e}")
  38. return False
  39. def _sync_linux(self) -> bool:
  40. """Linux系统时间同步"""
  41. for server in self.ntp_servers:
  42. try:
  43. logger.info(f"尝试从 {server} 同步时间...")
  44. # 使用echo命令自动输入密码
  45. cmd = f'echo "12345678" | sudo -S ntpdate {server}'
  46. result = subprocess.run(
  47. cmd,
  48. shell=True,
  49. capture_output=True,
  50. text=True,
  51. timeout=30
  52. )
  53. if result.returncode == 0:
  54. logger.info(f"时间同步成功: {result.stdout.strip()}")
  55. return True
  56. else:
  57. logger.warning(
  58. f"从 {server} 同步失败: {result.stderr.strip()}")
  59. except subprocess.TimeoutExpired:
  60. logger.warning(f"从 {server} 同步超时")
  61. except subprocess.CalledProcessError as e:
  62. logger.warning(f"从 {server} 同步失败: {e}")
  63. except FileNotFoundError:
  64. logger.error("未找到ntpdate命令,请安装ntpdate工具")
  65. return False
  66. except Exception as e:
  67. logger.warning(f"从 {server} 同步异常: {e}")
  68. logger.error("所有NTP服务器同步失败")
  69. return False
  70. def _sync_windows(self) -> bool:
  71. """Windows系统时间同步"""
  72. try:
  73. logger.info("Windows系统时间同步...")
  74. # 使用w32tm命令同步时间
  75. result = subprocess.run(
  76. ["w32tm", "/resync"],
  77. capture_output=True,
  78. text=True,
  79. timeout=30
  80. )
  81. if result.returncode == 0:
  82. logger.info("Windows时间同步成功")
  83. return True
  84. else:
  85. logger.warning(f"Windows时间同步失败: {result.stderr.strip()}")
  86. return False
  87. except subprocess.TimeoutExpired:
  88. logger.warning("Windows时间同步超时")
  89. return False
  90. except subprocess.CalledProcessError as e:
  91. logger.warning(f"Windows时间同步失败: {e}")
  92. return False
  93. except Exception as e:
  94. logger.error(f"Windows时间同步异常: {e}")
  95. return False
  96. def get_current_time(self) -> str:
  97. """
  98. 获取当前系统时间
  99. Returns:
  100. str: 格式化的当前时间
  101. """
  102. return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
  103. def check_time_drift(self) -> Optional[float]:
  104. """
  105. 检查时间偏差(需要网络连接)
  106. Returns:
  107. Optional[float]: 时间偏差(秒),失败返回None
  108. """
  109. try:
  110. import requests
  111. import datetime
  112. # 获取网络时间
  113. response = requests.get(
  114. "http://worldtimeapi.org/api/timezone/Asia/Shanghai", timeout=5)
  115. if response.status_code == 200:
  116. data = response.json()
  117. network_time = datetime.datetime.fromisoformat(
  118. data['datetime'].replace('Z', '+00:00'))
  119. # 获取本地时间
  120. local_time = datetime.datetime.now()
  121. # 计算时间差
  122. time_diff = abs((network_time - local_time).total_seconds())
  123. return time_diff
  124. except Exception as e:
  125. logger.debug(f"检查时间偏差失败: {e}")
  126. return None
  127. def sync_system_time() -> bool:
  128. """
  129. 同步系统时间的便捷函数
  130. Returns:
  131. bool: 同步是否成功
  132. """
  133. time_sync = TimeSync()
  134. return time_sync.sync_time()