From 7572a66ae2c842bdab52fe5e01d6c235b554f3e2 Mon Sep 17 00:00:00 2001 From: Simon Diesenreiter Date: Tue, 15 Apr 2025 15:06:29 +0200 Subject: [PATCH] fix: add direct CronTimer reference refs NOISSUE --- CronTimer/CronEventArgs.cs | 6 ++ CronTimer/CronTimer.cs | 78 ++++++++++++++++++++++++++ CronTimer/CronTimer.csproj | 49 ++++++++++++++++ CronTimer/CronTimer.sln | 36 ++++++++++++ song_of_the_day/song_of_the_day.csproj | 3 + 5 files changed, 172 insertions(+) create mode 100644 CronTimer/CronEventArgs.cs create mode 100644 CronTimer/CronTimer.cs create mode 100644 CronTimer/CronTimer.csproj create mode 100644 CronTimer/CronTimer.sln diff --git a/CronTimer/CronEventArgs.cs b/CronTimer/CronEventArgs.cs new file mode 100644 index 0000000..df87ec1 --- /dev/null +++ b/CronTimer/CronEventArgs.cs @@ -0,0 +1,6 @@ +using System; + +public class CronTimerEventArgs : EventArgs +{ + public DateTime At { get; set; } +} diff --git a/CronTimer/CronTimer.cs b/CronTimer/CronTimer.cs new file mode 100644 index 0000000..00357a8 --- /dev/null +++ b/CronTimer/CronTimer.cs @@ -0,0 +1,78 @@ +using System; +using System.Threading; +using NCrontab; + +public class CronTimer +{ + public const string UTC = "Etc/UTC"; + + static readonly TimeSpan InfiniteTimeSpan = TimeSpan.FromMilliseconds(Timeout.Infinite); // net 3.5 + + readonly CrontabSchedule schedule; + readonly TimeZoneInfo tzi; + readonly string id; + readonly Timer t; + + public string tz { get; } + public string Expression { get; } + public event EventHandler OnOccurence; + + public DateTime Next { get; private set; } + + public CronTimer(string expression, string tz = UTC, bool includingSeconds = false) + { + Expression = expression; + this.tz = tz; + id = TimeZoneConverter.TZConvert.IanaToWindows(tz); + tzi = TimeZoneInfo.FindSystemTimeZoneById(id); + schedule = CrontabSchedule.Parse(expression, new CrontabSchedule.ParseOptions { IncludingSeconds = includingSeconds }); + Next = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tzi); + OnOccurence += OnOccurenceScheduleNext; + t = new Timer(s => + { + var ea = new CronTimerEventArgs + { + At = Next + }; + OnOccurence(this, ea); + }, null, InfiniteTimeSpan, InfiniteTimeSpan); + } + + void OnOccurenceScheduleNext(object sender, EventArgs e) + { + var delay = CalculateDelay(); + //Console.WriteLine($"Next for [{tz} {expression}] in {delay}."); + t.Change(delay, InfiniteTimeSpan); + } + + public void Start() + { + var delay = CalculateDelay(); + //Console.WriteLine($"Next for [{tz} {expression}] in {delay}."); + t.Change(delay, InfiniteTimeSpan); + } + + TimeSpan CalculateDelay() + { + var nowUtc = DateTime.UtcNow; + Next = schedule.GetNextOccurrence(Next); + TimeSpan delay; + if (tz != UTC) + { + var nextUtc = TimeZoneInfo.ConvertTimeToUtc(Next, tzi); + delay = nextUtc - nowUtc; + } + else + { + delay = Next - nowUtc; + } + //Console.WriteLine($"Now: {nowUtc} [utc] {now} [{tz}], Next: {next} [{tz}] {nextUtc} [utc], Delay: {delay}"); + if (delay < TimeSpan.Zero) delay = TimeSpan.Zero; + return delay; + } + + public void Stop() + { + t.Change(InfiniteTimeSpan, InfiniteTimeSpan); + } +} diff --git a/CronTimer/CronTimer.csproj b/CronTimer/CronTimer.csproj new file mode 100644 index 0000000..f488cf3 --- /dev/null +++ b/CronTimer/CronTimer.csproj @@ -0,0 +1,49 @@ + + + + latest + net461;netstandard2.1 + AnyCPU + + + + + 2.0.1 + + $(FileVersion) + + 2.0.0.0 + + $(Version) + CronTimer + https://github.com/ramonsmits + ramonsmits + Simple .net Timer that is based on cron expressions with second accuracy to fire timer events to a very specific schedule. + false + + https://github.com/ramonsmits/CronTimer/tree/$(PackageVersion) + MIT + True + snupkg + True + https://github.com/ramonsmits/CronTimer + Copyright 2022 (c) Ramon Smits + cron timer + true + true + true + true + + + + + + + + + + diff --git a/CronTimer/CronTimer.sln b/CronTimer/CronTimer.sln new file mode 100644 index 0000000..adc7e3f --- /dev/null +++ b/CronTimer/CronTimer.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30717.126 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CronTimer", "CronTimer.csproj", "{FB64C227-8615-4AE1-94E3-F9F9DF192B72}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CCDD0B34-653C-430C-9B17-5129618F8D7D}" + ProjectSection(SolutionItems) = preProject + ..\README.md = ..\README.md + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo", "..\Demo\Demo.csproj", "{C2638357-1621-4422-8701-B55BFB37ACCF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FB64C227-8615-4AE1-94E3-F9F9DF192B72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB64C227-8615-4AE1-94E3-F9F9DF192B72}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB64C227-8615-4AE1-94E3-F9F9DF192B72}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB64C227-8615-4AE1-94E3-F9F9DF192B72}.Release|Any CPU.Build.0 = Release|Any CPU + {C2638357-1621-4422-8701-B55BFB37ACCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2638357-1621-4422-8701-B55BFB37ACCF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2638357-1621-4422-8701-B55BFB37ACCF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2638357-1621-4422-8701-B55BFB37ACCF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A639B164-6581-40DF-ADC4-479DAB467CFE} + EndGlobalSection +EndGlobal diff --git a/song_of_the_day/song_of_the_day.csproj b/song_of_the_day/song_of_the_day.csproj index 246c091..443368d 100644 --- a/song_of_the_day/song_of_the_day.csproj +++ b/song_of_the_day/song_of_the_day.csproj @@ -21,4 +21,7 @@ + + + \ No newline at end of file