fix:issue #160
This commit is contained in:
@@ -70,6 +70,11 @@ namespace Ink_Canvas
|
|||||||
private TimeViewModel nowTimeVM = new TimeViewModel();
|
private TimeViewModel nowTimeVM = new TimeViewModel();
|
||||||
private DateTime cachedNetworkTime = DateTime.Now;
|
private DateTime cachedNetworkTime = DateTime.Now;
|
||||||
private DateTime lastNtpSyncTime = DateTime.MinValue;
|
private DateTime lastNtpSyncTime = DateTime.MinValue;
|
||||||
|
private string lastDisplayedTime = "";
|
||||||
|
private bool useNetworkTime = false;
|
||||||
|
private TimeSpan networkTimeOffset = TimeSpan.Zero;
|
||||||
|
private DateTime lastLocalTime = DateTime.Now; // 记录上次的本地时间,用于检测时间跳跃
|
||||||
|
private bool isNtpSyncing = false; // 防止重复NTP同步的标志
|
||||||
|
|
||||||
private async Task<DateTime> GetNetworkTimeAsync()
|
private async Task<DateTime> GetNetworkTimeAsync()
|
||||||
{
|
{
|
||||||
@@ -82,7 +87,7 @@ namespace Ink_Canvas
|
|||||||
var ipEndPoint = new IPEndPoint(addresses[0], 123);
|
var ipEndPoint = new IPEndPoint(addresses[0], 123);
|
||||||
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
|
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
|
||||||
{
|
{
|
||||||
socket.ReceiveTimeout = 2000;
|
socket.ReceiveTimeout = 5000;
|
||||||
socket.Connect(ipEndPoint);
|
socket.Connect(ipEndPoint);
|
||||||
await Task.Factory.FromAsync(socket.BeginSend(ntpData, 0, ntpData.Length, SocketFlags.None, null, socket), socket.EndSend);
|
await Task.Factory.FromAsync(socket.BeginSend(ntpData, 0, ntpData.Length, SocketFlags.None, null, socket), socket.EndSend);
|
||||||
await Task.Factory.FromAsync(socket.BeginReceive(ntpData, 0, ntpData.Length, SocketFlags.None, null, socket), socket.EndReceive);
|
await Task.Factory.FromAsync(socket.BeginReceive(ntpData, 0, ntpData.Length, SocketFlags.None, null, socket), socket.EndReceive);
|
||||||
@@ -94,7 +99,7 @@ namespace Ink_Canvas
|
|||||||
var networkDateTime = (new DateTime(1900, 1, 1)).AddMilliseconds((long)milliseconds);
|
var networkDateTime = (new DateTime(1900, 1, 1)).AddMilliseconds((long)milliseconds);
|
||||||
return networkDateTime.ToLocalTime();
|
return networkDateTime.ToLocalTime();
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return DateTime.Now;
|
return DateTime.Now;
|
||||||
}
|
}
|
||||||
@@ -114,7 +119,7 @@ namespace Ink_Canvas
|
|||||||
timerCheckAutoUpdateWithSilence.Interval = 1000 * 60 * 10;
|
timerCheckAutoUpdateWithSilence.Interval = 1000 * 60 * 10;
|
||||||
WaterMarkTime.DataContext = nowTimeVM;
|
WaterMarkTime.DataContext = nowTimeVM;
|
||||||
WaterMarkDate.DataContext = nowTimeVM;
|
WaterMarkDate.DataContext = nowTimeVM;
|
||||||
timerDisplayTime.Elapsed += async (s, e) => await TimerDisplayTime_ElapsedAsync();
|
timerDisplayTime.Elapsed += TimerDisplayTime_Elapsed;
|
||||||
timerDisplayTime.Interval = 1000;
|
timerDisplayTime.Interval = 1000;
|
||||||
timerDisplayTime.Start();
|
timerDisplayTime.Start();
|
||||||
timerDisplayDate.Elapsed += TimerDisplayDate_Elapsed;
|
timerDisplayDate.Elapsed += TimerDisplayDate_Elapsed;
|
||||||
@@ -126,63 +131,124 @@ namespace Ink_Canvas
|
|||||||
timerKillProcess.Start();
|
timerKillProcess.Start();
|
||||||
nowTimeVM.nowDate = DateTime.Now.ToString("yyyy'年'MM'月'dd'日' dddd");
|
nowTimeVM.nowDate = DateTime.Now.ToString("yyyy'年'MM'月'dd'日' dddd");
|
||||||
nowTimeVM.nowTime = DateTime.Now.ToString("tt hh'时'mm'分'ss'秒'");
|
nowTimeVM.nowTime = DateTime.Now.ToString("tt hh'时'mm'分'ss'秒'");
|
||||||
|
|
||||||
|
// 程序启动时立即进行一次NTP同步
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await TimerNtpSync_ElapsedAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"程序启动时NTP同步失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// NTP同步定时器事件处理
|
// NTP同步定时器事件处理
|
||||||
private async Task TimerNtpSync_ElapsedAsync()
|
private async Task TimerNtpSync_ElapsedAsync()
|
||||||
{
|
{
|
||||||
|
// 防止重复同步
|
||||||
|
if (isNtpSyncing) return;
|
||||||
|
|
||||||
|
isNtpSyncing = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DateTime networkTime = await GetNetworkTimeAsync();
|
|
||||||
|
// 添加超时机制,最多等待10秒
|
||||||
|
var timeoutTask = Task.Delay(10000);
|
||||||
|
var ntpTask = GetNetworkTimeAsync();
|
||||||
|
|
||||||
|
var completedTask = await Task.WhenAny(ntpTask, timeoutTask);
|
||||||
|
|
||||||
|
if (completedTask == timeoutTask)
|
||||||
|
{
|
||||||
|
cachedNetworkTime = DateTime.Now;
|
||||||
|
lastNtpSyncTime = DateTime.Now;
|
||||||
|
useNetworkTime = false;
|
||||||
|
networkTimeOffset = TimeSpan.Zero;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime networkTime = await ntpTask;
|
||||||
|
DateTime localTime = DateTime.Now;
|
||||||
|
|
||||||
cachedNetworkTime = networkTime;
|
cachedNetworkTime = networkTime;
|
||||||
lastNtpSyncTime = DateTime.Now;
|
lastNtpSyncTime = localTime;
|
||||||
}
|
|
||||||
catch
|
// 计算网络时间与本地时间的偏移量
|
||||||
|
networkTimeOffset = networkTime - localTime;
|
||||||
|
|
||||||
|
// 如果时间差超过3分钟,则使用网络时间
|
||||||
|
useNetworkTime = Math.Abs(networkTimeOffset.TotalMinutes) > 3.0;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// NTP同步失败时,保持使用本地时间
|
// NTP同步失败时,保持使用本地时间
|
||||||
cachedNetworkTime = DateTime.Now;
|
cachedNetworkTime = DateTime.Now;
|
||||||
lastNtpSyncTime = DateTime.Now;
|
lastNtpSyncTime = DateTime.Now;
|
||||||
|
useNetworkTime = false;
|
||||||
|
networkTimeOffset = TimeSpan.Zero;
|
||||||
|
|
||||||
|
LogHelper.WriteLogToFile($"NTP同步失败: {ex.Message}", LogHelper.LogType.Warning);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
isNtpSyncing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改TimerDisplayTime_ElapsedAsync方法,使用缓存的网络时间
|
// 优化后的时间显示方法,仅在NTP同步时计算网络时间偏移
|
||||||
private async Task TimerDisplayTime_ElapsedAsync()
|
private void TimerDisplayTime_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
DateTime localTime = DateTime.Now;
|
DateTime localTime = DateTime.Now;
|
||||||
DateTime displayTime = localTime; // 默认使用本地时间
|
DateTime displayTime = localTime; // 默认使用本地时间
|
||||||
|
|
||||||
// 如果还没有进行过NTP同步,或者距离上次同步超过2小时,则进行一次同步
|
// 检测系统时间是否发生重大跳跃(超过2分钟)
|
||||||
if (lastNtpSyncTime == DateTime.MinValue ||
|
TimeSpan timeJump = localTime - lastLocalTime;
|
||||||
(DateTime.Now - lastNtpSyncTime).TotalHours >= 2)
|
double timeJumpMinutes = Math.Abs(timeJump.TotalMinutes);
|
||||||
|
|
||||||
|
if (timeJumpMinutes > 3 && !isNtpSyncing)
|
||||||
{
|
{
|
||||||
try
|
// 系统时间发生重大变化(超过3分钟),立即触发NTP同步
|
||||||
|
// 使用异步方式触发NTP同步,避免阻塞主线程
|
||||||
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
DateTime networkTime = await GetNetworkTimeAsync();
|
try
|
||||||
cachedNetworkTime = networkTime;
|
{
|
||||||
lastNtpSyncTime = DateTime.Now;
|
await TimerNtpSync_ElapsedAsync();
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// 网络时间获取失败时,使用本地时间
|
LogHelper.WriteLogToFile($"时间跳跃触发的NTP同步失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
cachedNetworkTime = localTime;
|
}
|
||||||
lastNtpSyncTime = DateTime.Now;
|
});
|
||||||
}
|
}
|
||||||
|
lastLocalTime = localTime;
|
||||||
|
|
||||||
|
// 如果启用网络时间且偏移量已计算,则应用偏移量
|
||||||
|
if (useNetworkTime && networkTimeOffset != TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
displayTime = localTime + networkTimeOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用缓存的网络时间进行显示
|
// 格式化时间字符串
|
||||||
DateTime dynamicNetworkTime = cachedNetworkTime + (localTime - lastNtpSyncTime);
|
string timeString = displayTime.ToString("tt hh'时'mm'分'ss'秒'");
|
||||||
TimeSpan timeDifference = dynamicNetworkTime - localTime;
|
|
||||||
double timeDifferenceMinutes = Math.Abs(timeDifference.TotalMinutes);
|
|
||||||
|
|
||||||
// 如果网络时间与本地时间相差不超过3分钟,则使用本地时间
|
|
||||||
// 否则使用动态网络时间
|
// 只有当时间字符串发生变化时才更新UI,避免不必要的UI刷新
|
||||||
displayTime = timeDifferenceMinutes <= 3.0 ? localTime : dynamicNetworkTime;
|
if (timeString != lastDisplayedTime)
|
||||||
|
|
||||||
// 只更新时间,日期由原有逻辑定时更新即可
|
|
||||||
Dispatcher.Invoke(() =>
|
|
||||||
{
|
{
|
||||||
nowTimeVM.nowTime = displayTime.ToString("tt hh'时'mm'分'ss'秒'");
|
lastDisplayedTime = timeString;
|
||||||
});
|
|
||||||
|
// 使用BeginInvoke异步更新UI,避免阻塞
|
||||||
|
Dispatcher.BeginInvoke(new Action(() =>
|
||||||
|
{
|
||||||
|
nowTimeVM.nowTime = timeString;
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改TimerDisplayDate_Elapsed方法中的日期格式
|
// 修改TimerDisplayDate_Elapsed方法中的日期格式
|
||||||
|
|||||||
Reference in New Issue
Block a user