C# 实现时间来到新的一天时触发事
独立观察员 2023 年 12 月 19 日
看到知乎有人提问《C# 如果要实现一个任务每天 0 点执行,用什么方法等待更高效?》,回想起之前写过的一个方法,现在翻出来大家讨论讨论。
新建一个时间事件帮助类(单例),通过定时器,到第二天 0 点后触发 [新的一天] 事件,使用的地方订阅这个事件即可。
/// <summary> | |
/// 时间事件帮助类 | |
/// </summary> | |
public class TimeEventHelper | |
{ | |
/// <summary> | |
/// 私有构造函数,防止从外边实例化 | |
/// </summary> | |
private TimeEventHelper() | |
{ | |
_NewDayTimer.Interval = 1000 * (DateHelper.GetTodaySecond() + 2); | |
WriteLog($"【定时器】将在 {DateTime.Now.AddMilliseconds(_NewDayTimer.Interval):yyyy-MM-dd HH:mm:ss} 触发 [新的一天] 事件 "); | |
_NewDayTimer.Elapsed += NewDayTimerHandler; | |
} | |
/// <summary> | |
/// 公有静态成员方法,返回唯一实例 | |
/// </summary> | |
/// <returns> 单例 </returns> | |
public static TimeEventHelper GetInstance() | |
{ | |
return InnerClass.instance; | |
} | |
/// <summary> | |
/// 内部类,第一次调用 GetInstance () 时加载 InnerClass | |
/// </summary> | |
class InnerClass | |
{ | |
// 在类被实例化或静态成员被调用的时候进行调用 | |
// 这里也就是当 instance 被调用的时候,会执行静态函数,初始化成员变量 | |
static InnerClass() { } | |
internal static readonly TimeEventHelper instance = new TimeEventHelper(); | |
} | |
/// <summary> | |
/// [新的一天] 判断定时器 | |
/// </summary> | |
private readonly Timer _NewDayTimer = new Timer(1000) { AutoReset = true, Enabled = true }; | |
/// <summary> | |
/// [新的一天] 事件 | |
/// </summary> | |
public event Action NewDayEvent; | |
/// <summary> | |
/// 写日志 | |
/// </summary> | |
/// <param name="logStr"> 日志内容 </param> | |
private void WriteLog(string logStr) | |
{ | |
LogManager.GetCurrentClassLogger().Debug(logStr); | |
} | |
/// <summary> | |
/// [新的一天] 定时器执行方法 | |
/// </summary> | |
public void NewDayTimerHandler(object source, System.Timers.ElapsedEventArgs e) | |
{ | |
try | |
{ | |
string eventName = "新的一天"; | |
WriteLog($" 开始触发 [{eventName}] 事件..."); | |
_NewDayTimer.Stop(); | |
NewDayEvent?.Invoke(); | |
WriteLog($" 触发 [{eventName}] 事件完成."); | |
_NewDayTimer.Interval = 1000 * (DateHelper.GetTodaySecond() + 2); | |
WriteLog($"【定时器】将在 {DateTime.Now.AddMilliseconds(_NewDayTimer.Interval):yyyy-MM-dd HH:mm:ss} 触发 [{eventName}] 事件 "); | |
_NewDayTimer.Start(); | |
} | |
catch (Exception ex) | |
{ | |
WriteLog($"[新的一天] 定时器执行方法中异常:{ex}"); | |
} | |
} | |
} |
定时器的时间间隔是关键,使用一个方法来获取当天剩余秒数,并在触发后重新设置:
/// <summary> | |
/// 获取当日的剩余 / 已过秒数 | |
/// </summary> | |
/// <param name="isRest"> 是否获取剩余秒数 </param> | |
/// <returns> 秒数 </returns> | |
public static double GetTodaySecond(bool isRest = true) | |
{ | |
if (isRest) | |
{ | |
DateTime dtime = DateTime.Today.AddDays(1).Date; | |
TimeSpan ts = dtime - DateTime.Now; | |
return ts.TotalSeconds; | |
} | |
else | |
{ | |
DateTime dtime = DateTime.Today.Date; | |
TimeSpan ts = DateTime.Now - dtime; | |
return ts.TotalSeconds; | |
} | |
} |
使用示例:
原创文章,转载请注明: 转载自 独立观察员 (dlgcy.com)