using System;
using System.ComponentModel;
using System.Globalization;
using System.Text.Json.Nodes;
namespace Sim.Host;
///
/// 虚拟时钟(实训台上可以拨时间、调倍速;教材项目 7 按时刻切换情景模式)。
/// 编译时把学生代码里的 DateTime.Now / Today / UtcNow 改写成这里的属性(见 Sim.Runner/ClockRewriter.cs)。
/// 没有拨过时就是真实时间。
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static class SimClock
{
private sealed record Setting(DateTime Wall, long RealAt, double Speed);
private static volatile Setting? _setting;
public static DateTime Now
{
get
{
var setting = _setting;
if (setting == null) return DateTime.Now;
var elapsed = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - setting.RealAt;
return setting.Wall.AddMilliseconds(elapsed * setting.Speed);
}
}
public static DateTime Today => Now.Date;
public static DateTime UtcNow => Now.ToUniversalTime();
/// 平台内部使用:应用服务器推送的 {"wall":"2024-01-16T06:40:00","realAt":…,"speed":60},null 恢复真实时间
public static void Update(JsonNode? clock)
{
if (clock is not JsonObject json
|| !DateTime.TryParseExact((string?)json["wall"], "yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var wall))
{
_setting = null;
return;
}
_setting = new Setting(DateTime.SpecifyKind(wall, DateTimeKind.Local), (long?)json["realAt"] ?? 0, (double?)json["speed"] ?? 1);
}
}