diff --git a/Pfr.Services.Scheduler.sln b/Pfr.Services.Scheduler.sln
new file mode 100644
index 0000000..95c5de4
--- /dev/null
+++ b/Pfr.Services.Scheduler.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32112.339
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pfr.Services.Scheduler", "Pfr.Services.Scheduler\Pfr.Services.Scheduler.csproj", "{7D0E3F8D-917D-41CF-B093-A5365C8F24F3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pfr.Services.SchedulerTests", "Pfr.Services.SchedulerTests\Pfr.Services.SchedulerTests.csproj", "{02192A90-645F-4DBC-866D-A1E890905C44}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7D0E3F8D-917D-41CF-B093-A5365C8F24F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7D0E3F8D-917D-41CF-B093-A5365C8F24F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7D0E3F8D-917D-41CF-B093-A5365C8F24F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7D0E3F8D-917D-41CF-B093-A5365C8F24F3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {02192A90-645F-4DBC-866D-A1E890905C44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {02192A90-645F-4DBC-866D-A1E890905C44}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {02192A90-645F-4DBC-866D-A1E890905C44}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {02192A90-645F-4DBC-866D-A1E890905C44}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {5079223D-206D-44BE-8FB5-E7AB3657172D}
+ EndGlobalSection
+EndGlobal
diff --git a/Pfr.Services.Scheduler/Pfr.Services.Scheduler.csproj b/Pfr.Services.Scheduler/Pfr.Services.Scheduler.csproj
new file mode 100644
index 0000000..079c661
--- /dev/null
+++ b/Pfr.Services.Scheduler/Pfr.Services.Scheduler.csproj
@@ -0,0 +1,11 @@
+
+
+
+ net6.0
+ enable
+ enable
+ True
+ $(VersionPrefix)1.2.3
+
+
+
diff --git a/Pfr.Services.Scheduler/Scheduler.cs b/Pfr.Services.Scheduler/Scheduler.cs
new file mode 100644
index 0000000..92be441
--- /dev/null
+++ b/Pfr.Services.Scheduler/Scheduler.cs
@@ -0,0 +1,86 @@
+namespace Pfr.Services.Scheduler
+{
+ public class Scheduler
+ {
+ private long _Interval = 1000;
+ private Timer _timer;
+ private TimerCallback _timerCallback;
+ private TimeExec _TimeExec;
+ private DateTime _DateTimeExec;
+
+ ///
+ ///
+ ///
+ ///
+ public Scheduler(TimeExec pTimeExec)
+ {
+ _timerCallback = new TimerCallback(CheckTime);
+ _timer = new Timer(_timerCallback, null, 0, _Interval);
+
+ _TimeExec = pTimeExec;
+ if(DateTime.Now.Hour <= pTimeExec.Hour)
+ {
+ if(DateTime.Now.Minute < pTimeExec.Minute)
+ {
+ //Todo-OK устанавливаем время запуска сегодня
+ _DateTimeExec = new DateTime(DateTime.Now.Year,
+ DateTime.Now.Month,
+ DateTime.Now.Day,
+ pTimeExec.Hour,
+ pTimeExec.Minute,
+ pTimeExec.Second);
+ }
+ else
+ {
+ //Todo-OK устанавливаем время запуска завтра
+ _DateTimeExec = new DateTime(DateTime.Now.Year,
+ DateTime.Now.Month,
+ DateTime.Now.Day,
+ pTimeExec.Hour,
+ pTimeExec.Minute,
+ pTimeExec.Second);
+ _DateTimeExec = _DateTimeExec.AddDays(1);
+ }
+ }
+ else
+ {
+ //Todo-OK устанавливаем время запуска завтра
+ _DateTimeExec = new DateTime(DateTime.Now.Year,
+ DateTime.Now.Month,
+ DateTime.Now.Day,
+ pTimeExec.Hour,
+ pTimeExec.Minute,
+ pTimeExec.Second);
+ _DateTimeExec = _DateTimeExec.AddDays(1);
+ }
+ }
+
+ public delegate void CheckTimeHandler(DateTime pDateTimeExec);
+ //public delegate void CheckTimeHandler();
+
+ public event CheckTimeHandler? OnExecute;
+ private void CheckTime(object obj)
+ {
+ if (Run())
+ {
+ OnExecute?.Invoke(_DateTimeExec);
+ _DateTimeExec = _DateTimeExec.AddHours(24);
+ }
+ }
+
+ private bool Run()
+ {
+ bool _Exec = false;
+ DateTime _curDateTime = DateTime.Now;
+ _Exec = false;
+ if ((_curDateTime.Day == _DateTimeExec.Day)
+ &&(_curDateTime.Hour == _DateTimeExec.Hour)
+ && (_curDateTime.Minute == _DateTimeExec.Minute))
+ {
+ _Exec = true;
+ }
+ return _Exec;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Pfr.Services.Scheduler/TimeExec.cs b/Pfr.Services.Scheduler/TimeExec.cs
new file mode 100644
index 0000000..fa86d2b
--- /dev/null
+++ b/Pfr.Services.Scheduler/TimeExec.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Pfr.Services.Scheduler
+{
+ public class TimeExec
+ {
+ private readonly int DefaultHour = 0;
+ private readonly int DefaultMinute = 0;
+ private readonly int DefaultSecond = 0;
+
+
+ private int _Hour;
+ private int _Minute;
+ private int _Second;
+ public TimeExec()
+ {
+ _Hour = DefaultHour;
+ _Minute = DefaultMinute;
+ _Second = DefaultSecond;
+ }
+
+
+ ///
+ /// Конструктор время выполнения
+ ///
+ /// час от 0 до 23
+ /// мин от 0 до 59
+ ///
+ public TimeExec(int hour, int minute)
+ {
+ InitProp(hour, minute);
+ Second = DefaultSecond;
+ }
+
+ public TimeExec(int hour, int minute, int second)
+ {
+ InitProp(hour, minute);
+ if ((second > 59) || (second < 0))
+ {
+ throw new ArgumentException(string.Format("second value from 0 to 59 this value {0}", second));
+ }
+ Second = second;
+ }
+ private void InitProp(int hour, int minute)
+ {
+ if ((hour > 23) || (hour < 0))
+ {
+ throw new ArgumentException(string.Format("hour value from 0 to 23 this value {0}", hour));
+ }
+ if ((minute > 59) || (minute < 0))
+ {
+ throw new ArgumentException(string.Format("minute value from 0 to 59 this value {0}", minute));
+ }
+ Hour = hour;
+ Minute = minute;
+ }
+
+ ///
+ /// мин от 0 до 59
+ ///
+ public int Minute { get => _Minute; set => _Minute = value; }
+
+ ///
+ /// час от 0 до 23
+ ///
+ public int Hour { get => _Hour; set => _Hour = value; }
+ public int Second { get => _Second; set => _Second = value; }
+ }
+}
diff --git a/Pfr.Services.SchedulerTests/Pfr.Services.SchedulerTests.csproj b/Pfr.Services.SchedulerTests/Pfr.Services.SchedulerTests.csproj
new file mode 100644
index 0000000..f4609a7
--- /dev/null
+++ b/Pfr.Services.SchedulerTests/Pfr.Services.SchedulerTests.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net6.0
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Pfr.Services.SchedulerTests/SchedulerTests.cs b/Pfr.Services.SchedulerTests/SchedulerTests.cs
new file mode 100644
index 0000000..219c2c0
--- /dev/null
+++ b/Pfr.Services.SchedulerTests/SchedulerTests.cs
@@ -0,0 +1,64 @@
+using Xunit;
+using Pfr.Services.Scheduler;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Threading;
+
+namespace Pfr.Services.Scheduler.Tests
+{
+ public class SchedulerTests
+ {
+ private TimeExec _te;
+ private int _CntExec = 0;
+
+ public TimeExec GetTimeExec(int pSec)
+ {
+ TimeExec _TimeExec = new TimeExec();
+ DateTime _dateTime = DateTime.Now.AddSeconds(pSec);
+ _TimeExec.Hour = _dateTime.Hour;
+ _TimeExec.Minute = _dateTime.Minute;
+ return _TimeExec;
+ }
+
+ [Fact()]
+ public void SchedulerTest()
+ {
+ _te = GetTimeExec(2);
+ Scheduler _Scheduler = new Scheduler(_te);
+ _Scheduler.OnExecute += OnExecMetod;
+ Thread.Sleep(4000);
+ }
+
+ private void OnExecMetod(DateTime pDateTimeExec)
+ {
+ Assert.Equal(pDateTimeExec.Hour, DateTime.Now.Hour);
+ Assert.Equal(pDateTimeExec.Minute, DateTime.Now.Minute);
+ }
+
+ [Fact()]
+ public void Scheduler_Empty_OnExecute_Test()
+ {
+ _te = GetTimeExec(2);
+ Scheduler _Scheduler = new Scheduler(_te);
+ Thread.Sleep(4000);
+ }
+
+ [Fact()]
+ public void Scheduler_One_Exec_Test()
+ {
+ _te = GetTimeExec(60);
+ Scheduler _Scheduler = new Scheduler(_te);
+ _Scheduler.OnExecute += OnExec;
+ Thread.Sleep(120000);
+ Assert.Equal(_CntExec, 1);
+ }
+
+ private void OnExec(DateTime pDateTimeExec)
+ {
+ _CntExec += 1;
+ }
+ }
+}
\ No newline at end of file