From 9b32ee916cc26ea15d0625edab1d50fbf3b3b585 Mon Sep 17 00:00:00 2001 From: biss Date: Tue, 11 Aug 2026 08:57:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AD=A6=E4=B8=9A=E9=A2=84?= =?UTF-8?q?=E8=AD=A6=E7=9A=84=E6=8C=89=E6=97=B6=E5=AE=9A=E6=97=B6=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Scheduling/WarningCheckWorker.cs | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/Jiaowu.Api/Infrastructure/Scheduling/WarningCheckWorker.cs b/src/Jiaowu.Api/Infrastructure/Scheduling/WarningCheckWorker.cs index ad69b03..936d39e 100644 --- a/src/Jiaowu.Api/Infrastructure/Scheduling/WarningCheckWorker.cs +++ b/src/Jiaowu.Api/Infrastructure/Scheduling/WarningCheckWorker.cs @@ -7,6 +7,8 @@ namespace Jiaowu.Api.Infrastructure.Scheduling; public sealed class WarningCheckWorker(IServiceScopeFactory scopeFactory, ILogger logger) : BackgroundService { + private static readonly TimeZoneInfo ChinaTimeZone = ResolveChinaTimeZone(); + protected override async Task ExecuteAsync(CancellationToken ct) { while (!ct.IsCancellationRequested) @@ -25,22 +27,32 @@ public sealed class WarningCheckWorker(IServiceScopeFactory scopeFactory, ILogge private static async Task RunAsync(AppDbContext db, CancellationToken ct) { - var now = DateTime.UtcNow; - var dow = (int)now.DayOfWeek == 0 ? 7 : (int)now.DayOfWeek; - var currentMinute = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc); + var nowUtc = DateTime.UtcNow; + var chinaNow = TimeZoneInfo.ConvertTime( + new DateTimeOffset(nowUtc), + ChinaTimeZone); + var dow = (int)chinaNow.DayOfWeek == 0 ? 7 : (int)chinaNow.DayOfWeek; + var currentMinuteUtc = new DateTime( + nowUtc.Year, + nowUtc.Month, + nowUtc.Day, + nowUtc.Hour, + nowUtc.Minute, + 0, + DateTimeKind.Utc); var rules = await db.WarningRules .Where(r => r.IsEnabled && r.AutoCheckEnabled && - r.CheckHour == now.Hour && r.CheckMinute == now.Minute && + r.CheckHour == chinaNow.Hour && r.CheckMinute == chinaNow.Minute && (r.CheckDayOfWeek == null || r.CheckDayOfWeek == dow)) .ToListAsync(ct); foreach (var rule in rules) { - if (rule.LastCheckAt.HasValue && rule.LastCheckAt.Value >= currentMinute) + if (rule.LastCheckAt.HasValue && rule.LastCheckAt.Value >= currentMinuteUtc) continue; - rule.LastCheckAt = now; + rule.LastCheckAt = nowUtc; await db.SaveChangesAsync(ct); var studentIds = await db.Students.Where(x => x.Status == StudentStatus.Active).Select(x => x.Id).ToListAsync(ct); @@ -100,4 +112,23 @@ public sealed class WarningCheckWorker(IServiceScopeFactory scopeFactory, ILogge var gpa = grades.Average(x => x.GradePoint!.Value); return gpa < rule.Threshold ? new WarningRecord { StudentId = sid, Type = WarningType.LowGPA, TriggerValue = Math.Round(gpa, 2), Detail = $"平均绩点 {gpa:F2},低于预警阈值 {rule.Threshold}。", AcademicTermId = termId } : null; } + + private static TimeZoneInfo ResolveChinaTimeZone() + { + foreach (var id in new[] { "Asia/Shanghai", "China Standard Time" }) + { + try + { + return TimeZoneInfo.FindSystemTimeZoneById(id); + } + catch (TimeZoneNotFoundException) + { + } + catch (InvalidTimeZoneException) + { + } + } + + throw new InvalidOperationException("服务器未提供中国标准时间时区定义。"); + } }