2025-11-26 15:19:31 +10:00
using Microsoft.Extensions.Logging ;
2023-10-17 09:42:18 +10:00
using PARR.DAL.DomainModels ;
using PARR.DAL.Services.Interfaces ;
2026-04-13 16:58:30 +10:00
using PARR.Domain.Enums ;
2026-02-10 15:50:30 +10:00
using System.Text.Json ;
2023-10-17 09:42:18 +10:00
2026-01-23 16:18:56 +10:00
namespace PARR.DAL.NextRunServices.Subservices
2023-10-17 09:42:18 +10:00
{
internal class EsppScheduleTransformService : IEsppScheduleTransformService
{
private readonly IEsppSchTypeConfigService esppSchTypeConfigService ;
private readonly ILogger < EsppScheduleTransformService > logger ;
2025-11-26 15:19:31 +10:00
private static readonly Dictionary < string , int > monthDict = new Dictionary < string , int > ( )
2023-10-19 09:14:19 +10:00
{
{ "Январь" , 1 } ,
{ "Февраль" , 2 } ,
{ "Март" , 3 } ,
{ "Апрель" , 4 } ,
{ "Май" , 5 } ,
{ "Июнь" , 6 } ,
{ "Июль" , 7 } ,
{ "Август" , 8 } ,
{ "Сентябрь" , 9 } ,
{ "Октябрь" , 10 } ,
{ "Ноябрь" , 11 } ,
{ "Декабрь" , 12 }
} ;
2025-11-26 15:19:31 +10:00
private static readonly Dictionary < string , int > orderDict = new Dictionary < string , int > ( )
2023-10-19 09:14:19 +10:00
{
{ "Первый" , 1 } ,
{ "Второй" , 2 } ,
{ "Третий" , 3 } ,
{ "Четвертый" , 4 } ,
{ "Последний" , 5 }
} ;
2025-11-26 15:19:31 +10:00
private static readonly Dictionary < string , int > dwDict = new Dictionary < string , int > ( )
2023-10-19 09:14:19 +10:00
{
{ "Понедельник" , 1 } ,
{ "Вторник" , 2 } ,
{ "Среда" , 3 } ,
{ "Четверг" , 4 } ,
{ "Пятница" , 5 } ,
{ "Суббота" , 6 } ,
{ "Воскресенье" , 0 }
} ;
2024-02-05 16:05:02 +10:00
2024-09-18 16:32:45 +10:00
2024-02-05 16:05:02 +10:00
public EsppScheduleTransformService (
2024-07-05 15:17:48 +10:00
ILogger < EsppScheduleTransformService > logger ,
2026-01-23 16:18:56 +10:00
IEsppSchTypeConfigService esppSchTypeConfigService
2024-02-05 16:05:02 +10:00
)
2023-10-17 09:42:18 +10:00
{
this . esppSchTypeConfigService = esppSchTypeConfigService ;
this . logger = logger ;
}
2026-02-05 15:41:36 +10:00
public async Task < DateTimeOffset > GetNextDateAsync ( Guid jobGroupId , DateTimeOffset referenceDate , TimeSpan ? offset = null )
2023-10-17 09:42:18 +10:00
{
2025-11-26 15:19:31 +10:00
var esppSchedule = await GetEsppScheduleAsync ( jobGroupId ) ;
2024-09-18 16:32:45 +10:00
2026-02-05 15:41:36 +10:00
return GetNextDate ( esppSchedule , referenceDate , offset ) ;
2025-11-26 15:19:31 +10:00
}
2026-02-05 15:41:36 +10:00
private DateTimeOffset GetNextDate ( EsppScheduleDto esppSchedule , DateTimeOffset referenceDate , TimeSpan ? offset )
2025-11-26 15:19:31 +10:00
{
2026-02-09 15:48:30 +10:00
//offset - желательно передавать всегда, хотябы М С К , чтобы рассчитывались правильно даты, так как в ЕСПП все в М С К
2026-02-16 12:23:24 +10:00
logger . LogDebug ( "Начинаю рассчет nextRun по расписанию ЕСПП. Входные данные: date: {referenceDate}, offset: {offset}" , referenceDate , offset ) ;
2026-02-10 15:50:30 +10:00
2025-11-26 15:19:31 +10:00
var nextRun = referenceDate ;
2023-10-23 13:45:43 +10:00
2026-02-09 15:48:30 +10:00
//var finalOffset = new TimeSpan(3, 0, 0) + (offset ?? TimeSpan.Zero);
var finalOffset = offset ? ? TimeSpan . Zero ;
2026-02-05 15:41:36 +10:00
var offsetReferenceDate = referenceDate . ToOffset ( finalOffset ) ;
2026-02-10 15:50:30 +10:00
logger . LogDebug ( "Дата после добавления offset - {offsetReferenceDate}" , offsetReferenceDate ) ;
2026-02-05 15:41:36 +10:00
////---------
//// Для рассчета по М С К времени, потому что в ЮТС может быть еще В С К , а по М С К это уже ПНД
//var offsetReferenceDate = referenceDate.ToOffset(new TimeSpan(3, 0, 0));
////---------
//// может быть offset ,это работает когда смещение для У З ЕСПП и применение З О РГ
//if (offset.HasValue)
// offsetReferenceDate = offsetReferenceDate.Off(offsetReferenceDate.Offset + offset);
// //offsetReferenceDate = offsetReferenceDate.Add(offset.Value);
2025-11-28 12:35:18 +10:00
2023-10-18 10:09:51 +10:00
switch ( esppSchedule . TypeSchedule . Id )
{
2023-10-23 11:04:12 +10:00
case ( int ) EsppSchTypeScheduleEnum . Regularly :
2025-11-28 12:35:18 +10:00
nextRun = GetNextDateRegularly ( esppSchedule . Values , offsetReferenceDate ) ;
2024-09-18 16:32:45 +10:00
break ;
2023-10-19 09:14:19 +10:00
case ( int ) EsppSchTypeScheduleEnum . Weekly :
2025-11-28 12:35:18 +10:00
nextRun = GetNextDateWeekly ( esppSchedule . Values , offsetReferenceDate ) ;
2024-09-18 16:32:45 +10:00
break ;
2023-10-19 09:14:19 +10:00
case ( int ) EsppSchTypeScheduleEnum . Monthly :
2025-11-28 12:35:18 +10:00
nextRun = GetNextDateMonthly ( esppSchedule . Values , offsetReferenceDate ) ;
2024-09-18 16:32:45 +10:00
break ;
2023-10-19 09:14:19 +10:00
case ( int ) EsppSchTypeScheduleEnum . Monthly2 :
2025-11-28 12:35:18 +10:00
nextRun = GetNextDateMonthly2 ( esppSchedule . Values , offsetReferenceDate ) ;
2024-09-18 16:32:45 +10:00
break ;
2023-10-19 09:14:19 +10:00
case ( int ) EsppSchTypeScheduleEnum . Annually :
2025-11-28 12:35:18 +10:00
nextRun = GetNextDateAnnually ( esppSchedule . Values , offsetReferenceDate ) ;
2024-09-18 16:32:45 +10:00
break ;
2023-10-18 10:09:51 +10:00
case ( int ) EsppSchTypeScheduleEnum . Annually2 :
2025-11-28 12:35:18 +10:00
nextRun = GetNextDateAnnually2 ( esppSchedule . Values , offsetReferenceDate ) ;
2024-09-18 16:32:45 +10:00
break ;
2023-10-18 10:09:51 +10:00
}
2024-09-18 16:32:45 +10:00
2026-02-10 15:50:30 +10:00
logger . LogDebug ( "Рассчитанная дата, с учетом offset: {nextRun}" , nextRun ) ;
2025-11-28 12:35:18 +10:00
// Возвращаем обратно в ЮТС
nextRun = nextRun . ToOffset ( TimeSpan . Zero ) ;
2025-11-24 16:28:50 +10:00
2026-02-10 15:50:30 +10:00
logger . LogDebug ( "Рассчитанная дата с нулевым offset: {nextRun}" , nextRun ) ;
2024-09-18 16:32:45 +10:00
return nextRun ;
2023-10-17 09:42:18 +10:00
}
2026-02-09 15:48:30 +10:00
/// <summary>
/// Получить расписание из БД
/// </summary>
/// <param name="jobGroupId"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
2025-06-25 14:17:34 +10:00
private async Task < EsppScheduleDto > GetEsppScheduleAsync ( Guid jobGroupId )
2023-10-17 09:42:18 +10:00
{
2025-06-25 14:17:34 +10:00
var esppSchedule = await esppSchTypeConfigService . GetEsppScheduleDtoAsync ( jobGroupId ) ;
2023-10-17 09:42:18 +10:00
if ( esppSchedule = = null )
{
2025-06-25 14:17:34 +10:00
logger . LogError ( $"Н е найдено расписание в БД, jobId: {jobGroupId}" ) ;
throw new Exception ( $"Н е найдено расписание в БД, jobId: {jobGroupId}" ) ;
2023-10-17 09:42:18 +10:00
}
return esppSchedule ;
}
2023-10-18 10:09:51 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset GetNextDateRegularly ( List < EsppScheduleValDto > values , DateTimeOffset referenceDate )
2023-10-23 11:04:12 +10:00
{
var regDict = new Dictionary < string , int >
{
2023-10-23 13:45:43 +10:00
{ "Каждый час" , 1 } ,
2023-10-23 11:04:12 +10:00
{ "Каждые 2 часа" , 2 } ,
{ "Каждые 3 часа" , 3 } ,
{ "Каждые 4 часа" , 4 } ,
{ "Каждые 6 часов" , 6 } ,
{ "Каждые 12 часов" , 12 } ,
{ "Ежедневно" , 24 } ,
{ "Каждые 72 часа" , 72 } ,
{ "Каждые 96 часов" , 96 } ,
{ "Каждые 2 недели" , 336 } ,
{ "Каждые 60 дней" , 1440 } ,
{ "Каждые 80 дней" , 1920 } ,
{ "Каждые 90 дней" , 2160 } ,
{ "Каждые полгода" , 4380 } ,
{ "Каждые 1,5 года" , 13140 } ,
{ "Каждые 3 года" , 26280 } ,
2025-11-28 12:35:18 +10:00
} ;
2023-10-23 11:04:12 +10:00
2025-11-26 15:19:31 +10:00
if ( ! regDict . TryGetValue ( values [ 0 ] . Value . Value , out int regNum ) )
{
logger . LogError ( "Неизвестное значение: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
2023-10-23 13:45:43 +10:00
2025-11-27 14:21:27 +10:00
var calcDay = referenceDate ;
2023-10-23 13:45:43 +10:00
2023-10-23 11:04:12 +10:00
//TODO: вот это повторяется от метода к методу
2024-09-16 17:01:04 +10:00
//Если итоговая дата указывает на прошлое, то повторяем расчёт и уходим в рекурсию
2023-10-23 11:04:12 +10:00
if ( calcDay < DateTimeOffset . UtcNow )
2025-11-26 15:19:31 +10:00
calcDay = GetNextDateRegularly ( values , calcDay . AddHours ( regNum ) ) ;
2023-10-23 11:04:12 +10:00
return calcDay ;
}
2024-09-16 17:01:04 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset GetNextDateWeekly ( List < EsppScheduleValDto > values , DateTimeOffset referenceDate )
2023-10-19 09:14:19 +10:00
{
2025-11-26 15:19:31 +10:00
if ( ! dwDict . TryGetValue ( values [ 0 ] . Value . Value , out int dwNum ) )
{
logger . LogError ( "Неизвестное значение дня недели: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
2023-10-19 09:14:19 +10:00
2025-11-26 15:19:31 +10:00
var calcDay = referenceDate ;
if ( calcDay < DateTimeOffset . UtcNow )
2026-02-09 15:48:30 +10:00
{
var nowInTargetTz = DateTimeOffset . UtcNow . ToOffset ( referenceDate . Offset ) ;
calcDay = new DateTimeOffset (
nowInTargetTz . Year ,
//DateTimeOffset.UtcNow.Year,
nowInTargetTz . Month ,
//DateTimeOffset.UtcNow.Month,
nowInTargetTz . Day ,
//DateTimeOffset.UtcNow.Day,
referenceDate . Hour ,
referenceDate . Minute ,
referenceDate . Second ,
referenceDate . Offset
) ;
}
2023-10-19 09:14:19 +10:00
if ( ( ( int ) calcDay . DayOfWeek ) ! = dwNum )
2025-11-26 15:19:31 +10:00
calcDay = OffsetToDayOfWeek ( dwNum , calcDay ) ;
2023-10-19 09:14:19 +10:00
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
if ( calcDay < DateTimeOffset . UtcNow )
2025-11-24 16:28:50 +10:00
calcDay = GetNextDateWeekly ( values , calcDay . AddDays ( 7 ) ) ; //а вот тут что-то новенькое
2023-10-19 09:14:19 +10:00
return calcDay ;
}
2024-09-16 17:01:04 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset GetNextDateMonthly ( List < EsppScheduleValDto > values , DateTimeOffset referenceDate )
2023-10-19 09:14:19 +10:00
{
2025-11-26 15:19:31 +10:00
if ( ! int . TryParse ( values [ 0 ] . Value . Value , out int dayNum ) )
{
logger . LogError ( "Неизвестное значение дня месяца: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
2025-11-24 16:28:50 +10:00
2025-11-26 15:19:31 +10:00
var calcDay = new DateTimeOffset ( referenceDate . Year , referenceDate . Month , dayNum , referenceDate . Hour , referenceDate . Minute , referenceDate . Second , referenceDate . Offset ) ;
if ( referenceDate < DateTimeOffset . UtcNow )
2026-02-09 15:48:30 +10:00
{
var nowInTargetTz = DateTimeOffset . UtcNow . ToOffset ( referenceDate . Offset ) ;
calcDay = new DateTimeOffset (
nowInTargetTz . Year ,
nowInTargetTz . Month ,
dayNum ,
referenceDate . Hour ,
referenceDate . Minute ,
referenceDate . Second ,
referenceDate . Offset
) ;
//calcDay = new DateTimeOffset(DateTimeOffset.UtcNow.Year, DateTimeOffset.UtcNow.Month, dayNum, referenceDate.Hour, referenceDate.Minute, referenceDate.Second, referenceDate.Offset);
}
2023-10-19 09:14:19 +10:00
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
if ( calcDay < DateTimeOffset . UtcNow )
2025-11-26 15:19:31 +10:00
calcDay = GetNextDateMonthly ( values , calcDay . AddMonths ( 1 ) ) ;
2023-10-19 09:14:19 +10:00
return calcDay ;
}
2024-09-16 17:01:04 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset GetNextDateMonthly2 ( List < EsppScheduleValDto > values , DateTimeOffset referenceDate )
2023-10-19 09:14:19 +10:00
{
2025-11-26 15:19:31 +10:00
if ( ! orderDict . TryGetValue ( values [ 0 ] . Value . Value , out int orderNum ) )
{
logger . LogError ( "Неизвестное значение порядка дня: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
2023-10-19 09:14:19 +10:00
2025-11-26 15:19:31 +10:00
if ( ! dwDict . TryGetValue ( values [ 1 ] . Value . Value , out int dwNum ) )
{
logger . LogError ( "Неизвестное значение дня недели: {Value}" , values [ 1 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[1].Value.Value}" ) ;
}
2025-11-24 16:28:50 +10:00
2026-02-09 15:48:30 +10:00
//var startDay = referenceDate < DateTimeOffset.UtcNow
// ? new DateTimeOffset(DateTimeOffset.UtcNow.Year, DateTimeOffset.UtcNow.Month, 1, referenceDate.Hour, referenceDate.Minute, referenceDate.Second, referenceDate.Offset)
// : new DateTimeOffset(referenceDate.Year, referenceDate.Month, 1, referenceDate.Hour, referenceDate.Minute, referenceDate.Second, referenceDate.Offset);
2025-11-26 15:19:31 +10:00
var startDay = referenceDate < DateTimeOffset . UtcNow
2026-02-09 15:48:30 +10:00
? new DateTimeOffset (
DateTimeOffset . UtcNow . ToOffset ( referenceDate . Offset ) . Year ,
DateTimeOffset . UtcNow . ToOffset ( referenceDate . Offset ) . Month ,
1 ,
referenceDate . Hour ,
referenceDate . Minute ,
referenceDate . Second ,
referenceDate . Offset
)
: new DateTimeOffset (
referenceDate . Year ,
referenceDate . Month ,
1 ,
referenceDate . Hour ,
referenceDate . Minute ,
referenceDate . Second ,
referenceDate . Offset
) ;
2023-10-19 09:14:19 +10:00
2025-11-26 15:19:31 +10:00
var daysList = FindAllDaysInMonth ( dwNum , startDay ) ;
2023-10-19 09:14:19 +10:00
2025-11-26 15:19:31 +10:00
DateTimeOffset calcDay ;
if ( orderNum = = 5 ) // Последний
{
2023-10-19 09:14:19 +10:00
calcDay = daysList . Last ( ) ;
2025-11-26 15:19:31 +10:00
}
2023-10-19 09:14:19 +10:00
else
2025-11-26 15:19:31 +10:00
{
if ( orderNum > daysList . Count )
{
logger . LogError ( "Запрошенный порядковый день недели ({OrderNum}) не существует в месяце {Month}/{Year}. Найдено только {Count} дней." , orderNum , startDay . Month , startDay . Year , daysList . Count ) ;
throw new InvalidOperationException ( $"Запрошенный порядковый день недели ({orderNum}) не существует в месяце {startDay.Month}/{startDay.Year}. Найдено только {daysList.Count} дней." ) ;
}
else
calcDay = daysList [ orderNum - 1 ] ;
}
2023-10-19 09:14:19 +10:00
2025-11-26 15:19:31 +10:00
// Если дата <= текущей, переходим на следующий месяц
if ( calcDay < = DateTimeOffset . UtcNow )
return GetNextDateMonthly2 ( values , startDay . AddMonths ( 1 ) ) ;
2023-10-19 09:14:19 +10:00
return calcDay ;
}
2024-09-16 17:01:04 +10:00
2025-11-27 14:21:27 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset GetNextDateAnnually ( List < EsppScheduleValDto > values , DateTimeOffset referenceDate )
2023-10-19 09:14:19 +10:00
{
2025-11-26 15:19:31 +10:00
if ( ! monthDict . TryGetValue ( values [ 0 ] . Value . Value , out int monthNum ) )
{
logger . LogError ( "Неизвестное значение номера месяца: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
if ( ! int . TryParse ( values [ 1 ] . Value . Value , out int dayNum ) )
{
logger . LogError ( "Неизвестное значение дня месяца: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
2026-02-09 15:48:30 +10:00
//var year = (referenceDate.Year < DateTimeOffset.UtcNow.Year) ? DateTimeOffset.UtcNow.Year : referenceDate.Year;
//сравниваем года в одном часовом поясе
var nowInTargetTz = DateTimeOffset . UtcNow . ToOffset ( referenceDate . Offset ) ;
var year = ( referenceDate . Year < nowInTargetTz . Year )
? nowInTargetTz . Year
: referenceDate . Year ;
2025-11-26 15:19:31 +10:00
var calcDay = new DateTimeOffset (
year , monthNum , dayNum ,
referenceDate . Hour , referenceDate . Minute , referenceDate . Second , referenceDate . Offset ) ;
2023-10-19 09:14:19 +10:00
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
if ( calcDay < DateTimeOffset . UtcNow )
2025-11-24 16:28:50 +10:00
calcDay = GetNextDateAnnually ( values , calcDay . AddYears ( 1 ) ) ;
2023-10-19 09:14:19 +10:00
return calcDay ;
}
2024-09-16 17:01:04 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset GetNextDateAnnually2 ( List < EsppScheduleValDto > values , DateTimeOffset referenceDate )
2023-10-18 10:09:51 +10:00
{
2023-10-19 09:14:19 +10:00
var monthADict = new Dictionary < string , int >
{
{ "Января" , 1 } ,
{ "Февраля" , 2 } ,
{ "Марта" , 3 } ,
{ "Апреля" , 4 } ,
{ "Мая" , 5 } ,
{ "Июня" , 6 } ,
{ "Июля" , 7 } ,
{ "Августа" , 8 } ,
{ "Сентября" , 9 } ,
{ "Октября" , 10 } ,
{ "Ноября" , 11 } ,
{ "Декабря" , 12 }
} ;
2025-11-26 15:19:31 +10:00
if ( ! monthADict . TryGetValue ( values [ 2 ] . Value . Value , out int monthNum ) )
{
logger . LogError ( "Неизвестное значение номера месяца: {Value}" , values [ 2 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[2].Value.Value}" ) ;
}
if ( ! orderDict . TryGetValue ( values [ 0 ] . Value . Value , out int orderNum ) )
{
logger . LogError ( "Неизвестное значение порядка дня: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
if ( ! dwDict . TryGetValue ( values [ 1 ] . Value . Value , out int dwNum ) )
{
logger . LogError ( "Неизвестное значение дня недели: {Value}" , values [ 1 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[1].Value.Value}" ) ;
}
2026-02-09 15:48:30 +10:00
//var year = (referenceDate.Year < DateTimeOffset.UtcNow.Year) ? DateTimeOffset.UtcNow.Year : referenceDate.Year;
// сравниваем года в одном часовом поясе
var nowInTargetTz = DateTimeOffset . UtcNow . ToOffset ( referenceDate . Offset ) ;
var year = ( referenceDate . Year < nowInTargetTz . Year )
? nowInTargetTz . Year
: referenceDate . Year ;
2025-11-26 15:19:31 +10:00
2026-02-09 15:48:30 +10:00
//if (year == DateTimeOffset.UtcNow.Year && referenceDate.Month < DateTimeOffset.UtcNow.Month)
if ( year = = nowInTargetTz . Year & & referenceDate . Month < nowInTargetTz . Month )
2025-11-26 15:19:31 +10:00
year + = 1 ;
2023-10-18 10:09:51 +10:00
2025-11-26 15:19:31 +10:00
var calcDay = new DateTimeOffset (
year , monthNum , 1 ,
referenceDate . Hour , referenceDate . Minute , referenceDate . Second , referenceDate . Offset ) ;
2023-10-18 10:09:51 +10:00
2025-11-26 15:19:31 +10:00
List < DateTimeOffset > daysList = FindAllDaysInMonth ( dwNum , calcDay ) ;
2023-10-18 10:09:51 +10:00
2023-10-19 09:14:19 +10:00
if ( orderNum = = 5 ) //5-последний
calcDay = daysList . Last ( ) ;
else
2025-11-26 15:19:31 +10:00
calcDay = daysList [ orderNum - 1 ] ;
2023-10-18 10:09:51 +10:00
2023-10-19 09:14:19 +10:00
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
if ( calcDay < DateTimeOffset . UtcNow )
2025-11-24 16:28:50 +10:00
calcDay = GetNextDateAnnually2 ( values , calcDay . AddYears ( 1 ) ) ;
2023-10-19 09:14:19 +10:00
return calcDay ;
}
2024-09-16 17:01:04 +10:00
2025-11-26 15:19:31 +10:00
private List < DateTimeOffset > FindAllDaysInMonth ( int dwNum , DateTimeOffset startDay )
2023-10-19 09:14:19 +10:00
{
2025-11-26 15:19:31 +10:00
var calcDay = startDay ;
2023-10-19 09:14:19 +10:00
if ( ( ( int ) calcDay . DayOfWeek ) ! = dwNum )
2025-11-26 15:19:31 +10:00
calcDay = OffsetToDayOfWeek ( dwNum , calcDay ) ;
2023-10-18 10:09:51 +10:00
var daysList = new List < DateTimeOffset > ( ) ;
2023-10-19 09:14:19 +10:00
var monthNum = calcDay . Month ;
2023-10-18 10:09:51 +10:00
while ( calcDay . Month = = monthNum )
{
daysList . Add ( calcDay ) ;
calcDay = calcDay . AddDays ( 7 ) ;
}
2023-10-19 09:14:19 +10:00
return daysList ;
2023-10-18 10:09:51 +10:00
}
2024-09-16 17:01:04 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset OffsetToDayOfWeek ( int dwNum , DateTimeOffset calcDay )
2023-10-19 09:14:19 +10:00
{
var daysOffset = dwNum - ( ( int ) calcDay . DayOfWeek ) ;
if ( daysOffset < 0 )
daysOffset = 7 + daysOffset ;
2025-11-26 15:19:31 +10:00
return calcDay . AddDays ( daysOffset ) ;
2023-10-19 09:14:19 +10:00
}
2024-07-02 11:43:59 +10:00
2023-10-17 09:42:18 +10:00
}
}