前言
在定位用户问题时,发现有些电脑,会出现系统时间不是最新的问题。
可能原因:
- 取消了勾选服务器时间同步
- 当前安装的系统,是一个未知来源系统,导致系统时间更新失败
而系统时间不正确,会导致IE选项-证书,校验不通过~
更新系统时间
1. 连接时间服务器
时间服务器列表(推荐): string[] timeHosts = { "time.windows.com", "time.nist.gov" };
1 /// <summary> 2 /// 连接时间服务器 3 /// </summary> 4 /// <param name="socket">服务器接口</param> 5 /// <param name="startTime">开始时间</param> 6 /// <param name="errorMsg">错误信息</param> 7 /// <returns></returns> 8 private static bool TryConnectToTimeServer(out Socket socket, out DateTime startTime, out string errorMsg) 9 { 10 socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建Socket 11 socket.ReceiveTimeout = 10 * 1000;//设置超时时间 12 errorMsg = string.Empty; 13 startTime = DateTime.Now; 14 15 // 遍历时间服务器列表 16 foreach (string strHost in timeHosts) 17 { 18 try 19 { 20 // 记录开始的时间 21 startTime = DateTime.Now; 22 23 var iphostinfo = Dns.GetHostEntry(strHost); 24 var ip = iphostinfo.AddressList[0]; 25 //建立IPAddress对象与端口,创建IPEndPoint节点: 26 int port = 13; 27 var ipe = new IPEndPoint(ip, port); 28 //连接到服务器 29 socket.Connect(ipe); 30 // 如果连接到服务器就跳出 31 if (socket.Connected) break; 32 } 33 catch (Exception ex) 34 { 35 errorMsg = $"时间服务器连接失败!/r错误信息:{ex.Message}系统提示"; 36 } 37 } 38 return socket.Connected; 39 }
2. 从服务器接收数据
1 /// <summary> 2 /// 从服务器接收数据 3 /// </summary> 4 /// <param name="socket"></param> 5 /// <returns></returns> 6 private static StringBuilder ReceiveMessageFromServer(Socket socket) 7 { 8 //SOCKET同步接受数据 9 byte[] receiveBytes = new byte[1024]; 10 int nBytes, nTotalBytes = 0; 11 StringBuilder sb = new StringBuilder(); 12 System.Text.Encoding encoding = Encoding.UTF8; 13 14 while ((nBytes = socket.Receive(receiveBytes, 0, 1024, SocketFlags.None)) > 0) 15 { 16 nTotalBytes += nBytes; 17 sb.Append(encoding.GetString(receiveBytes, 0, nBytes)); 18 } 19 20 return sb; 21 }
3. 更新本地时间
1 /// <summary> 2 /// 更新系统时间 3 /// </summary> 4 /// <returns>更新结果</returns> 5 public static string UpdateSystemTime() 6 { 7 try 8 { 9 var connected = TryConnectToTimeServer(out Socket socket, out var startTime, out string errorMsg); 10 if (connected) 11 { 12 var receivedMsg = ReceiveMessageFromServer(socket); 13 socket.Close(); 14 //切割字符串 15 string[] receiveMsgList = receivedMsg.ToString().Split(' '); 16 if (receiveMsgList.Length >= 3) 17 { 18 var dateTimeValue = receiveMsgList[1] + " " + receiveMsgList[2]; 19 SetLocalTime(startTime, dateTimeValue); 20 } 21 } 22 else 23 { 24 return errorMsg; 25 } 26 } 27 catch (Exception e) 28 { 29 return $"函数{nameof(UpdateSystemTime)}执行异常,{e.Message}"; 30 } 31 return "时间已同步"; 32 } 33 /// <summary> 34 /// 设置系统时间 35 /// </summary> 36 /// <param name="startTime">请求服务器时的开始时间</param> 37 /// <param name="dateTimeValue">服务器返回的时间</param> 38 private static void SetLocalTime(DateTime startTime, string dateTimeValue) 39 { 40 // 得到开始到现在所消耗的时间 41 TimeSpan k = DateTime.Now - startTime; 42 // 减去中途消耗的时间 43 DateTime updatedUtcTime = Convert.ToDateTime(dateTimeValue).Subtract(-k); 44 45 //处置北京时间 +8时 46 var updatedTime = updatedUtcTime.AddHours(8); 47 48 //转换System.DateTime到SystemTime 49 SystemTime systemTime = new SystemTime(); 50 systemTime.FromDateTime(updatedTime); 51 52 //调用Win32 API设置系统时间 53 Win32API.SetLocalTime(ref systemTime); 54 }
系统时间辅助类 & Win32API :
1 /// <summary> 2 /// 系统时间帮助类 3 /// </summary> 4 public struct SystemTime 5 { 6 public ushort wYear; 7 public ushort wMonth; 8 public ushort wDayOfWeek; 9 public ushort wDay; 10 public ushort wHour; 11 public ushort wMinute; 12 public ushort wSecond; 13 public ushort wMilliseconds; 14 15 /// <summary> 16 /// 从System.DateTime转换。 17 /// </summary> 18 /// <param name="time">System.DateTime类型的时间。</param> 19 public void FromDateTime(DateTime time) 20 { 21 wYear = (ushort)time.Year; 22 wMonth = (ushort)time.Month; 23 wDayOfWeek = (ushort)time.DayOfWeek; 24 wDay = (ushort)time.Day; 25 wHour = (ushort)time.Hour; 26 wMinute = (ushort)time.Minute; 27 wSecond = (ushort)time.Second; 28 wMilliseconds = (ushort)time.Millisecond; 29 } 30 /// <summary> 31 /// 转换为System.DateTime类型。 32 /// </summary> 33 /// <returns></returns> 34 public DateTime ToDateTime() 35 { 36 return new DateTime(wYear, wMonth, wDay, wHour, wMinute, wSecond, wMilliseconds); 37 } 38 /// <summary> 39 /// 静态方法。转换为System.DateTime类型。 40 /// </summary> 41 /// <param name="time">SYSTEMTIME类型的时间。</param> 42 /// <returns></returns> 43 public static DateTime ToDateTime(SystemTime time) 44 { 45 return time.ToDateTime(); 46 } 47 } 48 49 /// <summary> 50 /// 系统更新时间DLL 51 /// </summary> 52 public class Win32API 53 { 54 [DllImport("Kernel32.dll")] 55 public static extern bool SetLocalTime(ref SystemTime Time); 56 [DllImport("Kernel32.dll")] 57 public static extern void GetLocalTime(ref SystemTime Time); 58 }View Code