Compare commits

..

4 Commits

4 changed files with 420 additions and 140 deletions

View File

@@ -111,7 +111,7 @@
}
],
"RabbitMq": {
"ThresholdConnections": 29
"ThresholdConnections": 33
}
}
}

View File

@@ -70,23 +70,12 @@ namespace PARR.Core.Services.NextRunServices.Subservices
var nextRun = referenceDate;
//var finalOffset = new TimeSpan(3, 0, 0) + (offset ?? TimeSpan.Zero);
var finalOffset = offset ?? TimeSpan.Zero;
var offsetReferenceDate = referenceDate.ToOffset(finalOffset);
logger.LogDebug("Дата после добавления offset - {offsetReferenceDate}", offsetReferenceDate);
////---------
//// Для рассчета по МСК времени, потому что в ЮТС может быть еще ВСК, а по МСК это уже ПНД
//var offsetReferenceDate = referenceDate.ToOffset(new TimeSpan(3, 0, 0));
////---------
//// может быть offset ,это работает когда смещение для УЗ ЕСПП и применение ЗО РГ
//if (offset.HasValue)
// offsetReferenceDate = offsetReferenceDate.Off(offsetReferenceDate.Offset + offset);
// //offsetReferenceDate = offsetReferenceDate.Add(offset.Value);
switch (esppSchedule.TypeSchedule.Id)
{
@@ -108,6 +97,9 @@ namespace PARR.Core.Services.NextRunServices.Subservices
case (int)EsppSchTypeScheduleEnum.Annually2:
nextRun = GetNextDateAnnually2(esppSchedule.Values, offsetReferenceDate);
break;
default:
logger.LogError("Неподдерживаемый тип расписания ЕСПП: {TypeId}", esppSchedule.TypeSchedule.Id);
throw new NotSupportedException($"Тип расписания {esppSchedule.TypeSchedule.Id} не поддерживается.");
}
logger.LogDebug("Рассчитанная дата, с учетом offset: {nextRun}", nextRun);
@@ -139,6 +131,14 @@ namespace PARR.Core.Services.NextRunServices.Subservices
return esppSchedule;
}
/// <summary>
/// Регулярно. Каждые 1 час, 2 часа, Каждые пол года...
/// </summary>
/// <param name="values"></param>
/// <param name="referenceDate"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
private DateTimeOffset GetNextDateRegularly(List<EsppScheduleValDto> values, DateTimeOffset referenceDate)
{
var regDict = new Dictionary<string, int>
@@ -159,27 +159,63 @@ namespace PARR.Core.Services.NextRunServices.Subservices
{"Каждые полгода", 4380},
{"Каждые 1,5 года", 13140},
{"Каждые 3 года", 26280},
};
if (!regDict.TryGetValue(values[0].Value.Value, out int regNum))
var key = values[0].Value.Value;
if (!regDict.TryGetValue(key, out int regMinutes))
{
logger.LogError("Неизвестное значение: {Value}", values[0].Value.Value);
throw new ArgumentException($"Неизвестное значение: {values[0].Value.Value}");
logger.LogError("Неизвестное значение: {Value}", key);
throw new ArgumentException($"Неизвестное значение: {key}");
}
#region Старая логика
//var calcDay = referenceDate;
////TODO: вот это повторяется от метода к методу
////Если итоговая дата указывает на прошлое, то повторяем расчёт и уходим в рекурсию
//if (calcDay < DateTimeOffset.UtcNow /* || calcDay <= referenceDate*/)
// calcDay = GetNextDateRegularly(values, calcDay.AddHours(regMinutes));
//return calcDay;
#endregion
var nowInTargetZone = DateTimeOffset.UtcNow.ToOffset(referenceDate.Offset);
var calcDay = referenceDate;
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и уходим в рекурсию
if (calcDay < DateTimeOffset.UtcNow)
calcDay = GetNextDateRegularly(values, calcDay.AddHours(regNum));
// Если referenceDate далеко в прошлом, не шагаем по минутам в цикле.
// Сразу вычисляем, сколько целых интервалов нужно прибавить, чтобы догнать текущее время.
if (calcDay < nowInTargetZone)
{
double totalMinutesPast = (nowInTargetZone - calcDay).TotalMinutes;
return calcDay;
// Считаем, сколько полных интервалов помещается в этот отрезок времени
long intervalsToSkip = (long)Math.Ceiling(totalMinutesPast / regMinutes);
calcDay = calcDay.AddMinutes(intervalsToSkip * regMinutes);
}
// Проверяем условия и делаем микро-шаги, если необходимо
while (true)
{
if (calcDay >= referenceDate && calcDay >= nowInTargetZone)
{
return calcDay;
}
calcDay = calcDay.AddMinutes(regMinutes);
}
}
/// <summary>
/// Еженедельно, каждый понедельник, вторник, среду...
/// </summary>
/// <param name="values"></param>
/// <param name="referenceDate"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
private DateTimeOffset GetNextDateWeekly(List<EsppScheduleValDto> values, DateTimeOffset referenceDate)
{
if (!dwDict.TryGetValue(values[0].Value.Value, out int dwNum))
@@ -188,71 +224,155 @@ namespace PARR.Core.Services.NextRunServices.Subservices
throw new ArgumentException($"Неизвестное значение: {values[0].Value.Value}");
}
#region Старая логика
//var calcDay = referenceDate;
//if (calcDay < DateTimeOffset.UtcNow)
//{
// var nowInTargetTz = DateTimeOffset.UtcNow.ToOffset(referenceDate.Offset);
// calcDay = new DateTimeOffset(
// nowInTargetTz.Year,
// nowInTargetTz.Month,
// nowInTargetTz.Day,
// referenceDate.Hour,
// referenceDate.Minute,
// referenceDate.Second,
// referenceDate.Offset
// );
//}
//if (((int)calcDay.DayOfWeek) != dwNum)
// calcDay = OffsetToDayOfWeek(dwNum, calcDay);
////Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
//if (calcDay < DateTimeOffset.UtcNow || calcDay <= referenceDate)
// calcDay = GetNextDateWeekly(values, calcDay.AddDays(7));//а вот тут что-то новенькое
//return calcDay;
#endregion
var nowInTargetZone = DateTimeOffset.UtcNow.ToOffset(referenceDate.Offset);
var calcDay = referenceDate;
if (calcDay < DateTimeOffset.UtcNow)
// Сдвигаем дату вперед до нужного дня недели
if ((int)calcDay.DayOfWeek != dwNum)
{
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
);
calcDay = OffsetToDayOfWeek(dwNum, calcDay);
}
// Если получившаяся дата все еще глубоко в прошлом,
// не шагаем неделями в цикле, а мгновенно прыгаем ближе к текущему времени математикой.
if (calcDay < nowInTargetZone)
{
double totalDaysPast = (nowInTargetZone - calcDay).TotalDays;
if (((int)calcDay.DayOfWeek) != dwNum)
calcDay = OffsetToDayOfWeek(dwNum, calcDay);
// Вычисляем, сколько полных недель (по 7 дней) нужно прибавить
long weeksToSkip = (long)Math.Ceiling(totalDaysPast / 7);
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
if (calcDay < DateTimeOffset.UtcNow)
calcDay = GetNextDateWeekly(values, calcDay.AddDays(7));//а вот тут что-то новенькое
calcDay = calcDay.AddDays(weeksToSkip * 7);
}
return calcDay;
while (true)
{
// Условие выхода: дата в будущем относительно точки старта И текущего времени
if (calcDay >= referenceDate && calcDay >= nowInTargetZone)
{
return calcDay;
}
// Если условия не выполнены, делаем шаг ровно в одну неделю (7 дней)
calcDay = calcDay.AddDays(7);
}
}
/// <summary>
/// Ежемесячно, 1, 2, 3... числа
/// </summary>
/// <param name="values"></param>
/// <param name="referenceDate"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
private DateTimeOffset GetNextDateMonthly(List<EsppScheduleValDto> values, DateTimeOffset referenceDate)
{
if (!int.TryParse(values[0].Value.Value, out int dayNum))
if (!int.TryParse(values[0].Value.Value, out int targetDay))
{
logger.LogError("Неизвестное значение дня месяца: {Value}", values[0].Value.Value);
throw new ArgumentException($"Неизвестное значение: {values[0].Value.Value}");
}
var calcDay = new DateTimeOffset(referenceDate.Year, referenceDate.Month, dayNum, referenceDate.Hour, referenceDate.Minute, referenceDate.Second, referenceDate.Offset);
if (referenceDate < DateTimeOffset.UtcNow)
#region старая логика, не учтено попадание например 31 числа на февраль. Нет сравнения что расчитанная дата новее или равна refDate
//var calcDay = new DateTimeOffset(referenceDate.Year, referenceDate.Month, targetDay, referenceDate.Hour, referenceDate.Minute, referenceDate.Second, referenceDate.Offset);
//if (referenceDate < DateTimeOffset.UtcNow)
//{
// var nowInTargetTz = DateTimeOffset.UtcNow.ToOffset(referenceDate.Offset);
// calcDay = new DateTimeOffset(
// nowInTargetTz.Year,
// nowInTargetTz.Month,
// targetDay,
// referenceDate.Hour,
// referenceDate.Minute,
// referenceDate.Second,
// referenceDate.Offset
// );
//}
////Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
//if (calcDay < DateTimeOffset.UtcNow /*|| calcDay <= referenceDate*/)
// calcDay = GetNextDateMonthly(values, calcDay.AddMonths(1));
//return calcDay;
#endregion
// Начинаем проверку с текущего месяца и года переданной referenceDate
var baseDate = referenceDate;
int monthsToAdd = 0;
var nowInTargetZone = DateTimeOffset.UtcNow.ToOffset(referenceDate.Offset);
while (true)
{
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);
// Каждую итерацию мы отталкиваемся от исходной точки и прибавляем +1, +2, +3 месяца
var nextMonthDate = baseDate.AddMonths(monthsToAdd);
int year = nextMonthDate.Year;
int month = nextMonthDate.Month;
// Если в этом конкретном месяце НЕТ нужного нам дня (например, 31 числа в апреле или 30 в феврале)
if (targetDay > DateTime.DaysInMonth(year, month))
{
// Пропускаем этот месяц и идем на следующий круг цикла
monthsToAdd++;
continue;
}
// Если день существует, безопасно собираем дату
var calcDay = new DateTimeOffset(
year, month, targetDay,
referenceDate.Hour, referenceDate.Minute, referenceDate.Second,
referenceDate.Offset
);
// Условие выхода: дата строго в будущем относительно referenceDate и текущего UTC-времени
if (calcDay >= referenceDate && calcDay >= nowInTargetZone)
{
return calcDay;
}
// Если дата правильная, но она в прошлом — переходим к следующему месяцу
monthsToAdd++;
}
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
if (calcDay < DateTimeOffset.UtcNow)
calcDay = GetNextDateMonthly(values, calcDay.AddMonths(1));
return calcDay;
}
/// <summary>
/// Ежемесячно-2, Первый понедельник, Третий вторник
/// </summary>
/// <param name="values"></param>
/// <param name="referenceDate"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="InvalidOperationException"></exception>
private DateTimeOffset GetNextDateMonthly2(List<EsppScheduleValDto> values, DateTimeOffset referenceDate)
{
if (!orderDict.TryGetValue(values[0].Value.Value, out int orderNum))
@@ -267,56 +387,113 @@ namespace PARR.Core.Services.NextRunServices.Subservices
throw new ArgumentException($"Неизвестное значение: {values[1].Value.Value}");
}
#region Старая логика
//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);
// ? 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
// );
var startDay = referenceDate < DateTimeOffset.UtcNow
? 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
);
//var daysList = FindAllDaysInMonth(dwNum, startDay);
var daysList = FindAllDaysInMonth(dwNum, startDay);
//DateTimeOffset calcDay;
//if (orderNum == 5) // Последний
//{
// calcDay = daysList.Last();
//}
//else
//{
// 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];
//}
DateTimeOffset calcDay;
if (orderNum == 5) // Последний
//// Если дата <= текущей, переходим на следующий месяц
//if (calcDay <= DateTimeOffset.UtcNow /*|| calcDay <= referenceDate*/)
// return GetNextDateMonthly2(values, startDay.AddMonths(1));
//return calcDay;
#endregion
var nowInTargetZone = DateTimeOffset.UtcNow.ToOffset(referenceDate.Offset);
// Начинаем расчет с текущего месяца referenceDate
int monthsToAdd = 0;
while (true)
{
calcDay = daysList.Last();
}
else
{
if (orderNum > daysList.Count)
var currentMonthDate = referenceDate.AddMonths(monthsToAdd);
// Безопасно формируем первое число для проверяемого месяца
var startDayOfMonth = new DateTimeOffset(
currentMonthDate.Year,
currentMonthDate.Month,
1,
referenceDate.Hour,
referenceDate.Minute,
referenceDate.Second,
referenceDate.Offset
);
// Ищем все нужные дни недели в этом месяце
var daysList = FindAllDaysInMonth(dwNum, startDayOfMonth);
DateTimeOffset calcDay;
if (orderNum == 5) // Последний день недели в месяце (например, последняя пятница)
{
logger.LogError("Запрошенный порядковый день недели ({OrderNum}) не существует в месяце {Month}/{Year}. Найдено только {Count} дней.", orderNum, startDay.Month, startDay.Year, daysList.Count);
throw new InvalidOperationException($"Запрошенный порядковый день недели ({orderNum}) не существует в месяце {startDay.Month}/{startDay.Year}. Найдено только {daysList.Count} дней.");
calcDay = daysList.Last();
}
else
{
// Умная защита: если в текущем месяце нет 5-го вторника,
// мы не выкидываем ошибку приложения, а мягко идем искать в следующем месяце
if (orderNum > daysList.Count)
{
monthsToAdd++;
continue;
}
calcDay = daysList[orderNum - 1];
}
// 3. Условие выхода (точно такое же, как во всех предыдущих методах)
if (calcDay >= referenceDate && calcDay >= nowInTargetZone)
{
return calcDay;
}
// Если дата правильная, но она в прошлом — переходим к следующему календарному месяцу
monthsToAdd++;
}
// Если дата <= текущей, переходим на следующий месяц
if (calcDay <= DateTimeOffset.UtcNow)
return GetNextDateMonthly2(values, startDay.AddMonths(1));
return calcDay;
}
/// <summary>
/// Ежегодно, Январь 17, Февраль 20
/// </summary>
/// <param name="values"></param>
/// <param name="referenceDate"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
private DateTimeOffset GetNextDateAnnually(List<EsppScheduleValDto> values, DateTimeOffset referenceDate)
{
@@ -332,26 +509,73 @@ namespace PARR.Core.Services.NextRunServices.Subservices
throw new ArgumentException($"Неизвестное значение: {values[0].Value.Value}");
}
//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;
#region Старая логика
////сравниваем года в одном часовом поясе
//var nowInTargetTz = DateTimeOffset.UtcNow.ToOffset(referenceDate.Offset);
//var year = (referenceDate.Year < nowInTargetTz.Year)
// ? nowInTargetTz.Year
// : referenceDate.Year;
var calcDay = new DateTimeOffset(
year, monthNum, dayNum,
referenceDate.Hour, referenceDate.Minute, referenceDate.Second, referenceDate.Offset);
//var calcDay = new DateTimeOffset(
// year, monthNum, dayNum,
// referenceDate.Hour, referenceDate.Minute, referenceDate.Second, referenceDate.Offset);
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
if (calcDay < DateTimeOffset.UtcNow)
calcDay = GetNextDateAnnually(values, calcDay.AddYears(1));
////Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
//if (calcDay < DateTimeOffset.UtcNow /*|| calcDay <= referenceDate*/)
// calcDay = GetNextDateAnnually(values, calcDay.AddYears(1));
return calcDay;
//return calcDay;
#endregion
var nowInTargetZone = DateTimeOffset.UtcNow.ToOffset(referenceDate.Offset);
// Начинаем расчет с года переданной referenceDate
int yearsToAdd = 0;
while (true)
{
// Вычисляем текущий проверяемый год относительно исходной referenceDate
var currentYearDate = referenceDate.AddYears(yearsToAdd);
int year = currentYearDate.Year;
// ЗАЩИТА: Если в этом году нет такого дня (например, 29 февраля в невисокосном году)
if (dayNum > DateTime.DaysInMonth(year, monthNum))
{
// Просто пропускаем этот год и переходим к следующему
yearsToAdd++;
continue;
}
// Если день существует, безопасно собираем дату
var calcDay = new DateTimeOffset(
year,
monthNum,
dayNum,
referenceDate.Hour,
referenceDate.Minute,
referenceDate.Second,
referenceDate.Offset
);
// Проверяем условия выхода (абсолютно одинаково для всех методов)
if (calcDay >= referenceDate && calcDay >= nowInTargetZone)
{
return calcDay;
}
// Если дата в прошлом — переходим на следующий год
yearsToAdd++;
}
}
/// <summary>
/// Ежегодно-2, Первый понедельник января
/// </summary>
/// <param name="values"></param>
/// <param name="referenceDate"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
private DateTimeOffset GetNextDateAnnually2(List<EsppScheduleValDto> values, DateTimeOffset referenceDate)
{
var monthADict = new Dictionary<string, int>
@@ -386,34 +610,90 @@ namespace PARR.Core.Services.NextRunServices.Subservices
throw new ArgumentException($"Неизвестное значение: {values[1].Value.Value}");
}
//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;
//if (year == DateTimeOffset.UtcNow.Year && referenceDate.Month < DateTimeOffset.UtcNow.Month)
if (year == nowInTargetTz.Year && referenceDate.Month < nowInTargetTz.Month)
year += 1;
#region Старая логика
var calcDay = new DateTimeOffset(
year, monthNum, 1,
referenceDate.Hour, referenceDate.Minute, referenceDate.Second, referenceDate.Offset);
//// сравниваем года в одном часовом поясе
//var nowInTargetTz = DateTimeOffset.UtcNow.ToOffset(referenceDate.Offset);
//var year = (referenceDate.Year < nowInTargetTz.Year)
// ? nowInTargetTz.Year
// : referenceDate.Year;
List<DateTimeOffset> daysList = FindAllDaysInMonth(dwNum, calcDay);
////if (year == DateTimeOffset.UtcNow.Year && referenceDate.Month < DateTimeOffset.UtcNow.Month)
//if (year == nowInTargetTz.Year && referenceDate.Month < nowInTargetTz.Month)
// year += 1;
if (orderNum == 5)//5-последний
calcDay = daysList.Last();
else
calcDay = daysList[orderNum - 1];
//var calcDay = new DateTimeOffset(
// year, monthNum, 1,
// referenceDate.Hour, referenceDate.Minute, referenceDate.Second, referenceDate.Offset);
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
if (calcDay < DateTimeOffset.UtcNow)
calcDay = GetNextDateAnnually2(values, calcDay.AddYears(1));
//List<DateTimeOffset> daysList = FindAllDaysInMonth(dwNum, calcDay);
return calcDay;
//if (orderNum == 5)//5-последний
// calcDay = daysList.Last();
//else
// calcDay = daysList[orderNum - 1];
////Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
//if (calcDay < DateTimeOffset.UtcNow /*|| calcDay <= referenceDate*/)
// calcDay = GetNextDateAnnually2(values, calcDay.AddYears(1));
//return calcDay;
#endregion
var nowInTargetZone = DateTimeOffset.UtcNow.ToOffset(referenceDate.Offset);
// Начинаем расчет с года переданной referenceDate
int yearsToAdd = 0;
while (true)
{
// Сдвигаем проверяемый год относительно исходной даты
var currentYearDate = referenceDate.AddYears(yearsToAdd);
int year = currentYearDate.Year;
// Формируем первое число целевого месяца для проверяемого года
var startDayOfMonth = new DateTimeOffset(
year,
monthNum,
1,
referenceDate.Hour,
referenceDate.Minute,
referenceDate.Second,
referenceDate.Offset
);
// Ищем все нужные дни недели в этом месяце
var daysList = FindAllDaysInMonth(dwNum, startDayOfMonth);
DateTimeOffset calcDay;
if (orderNum == 5) // 5 означает "Последний день недели в месяце"
{
calcDay = daysList.Last();
}
else
{
// Умная защита: если в этом году в этом месяце НЕТ 5-го выбранного дня недели
if (orderNum > daysList.Count)
{
// Мы не падаем с ошибкой, а просто переходим к проверке следующего года
yearsToAdd++;
continue;
}
calcDay = daysList[orderNum - 1];
}
if (calcDay >= referenceDate && calcDay >= nowInTargetZone)
{
return calcDay;
}
// Если вычисленная дата в прошлом — переходим на следующий год
yearsToAdd++;
}
}

View File

@@ -29,7 +29,7 @@
"QueueName": "parr-next-run-updater",
"User": "next_run_updater_reader",
"Password": "LJFgsifgFidfsdvi123#!23",
"PrefetchCount": 100
"PrefetchCount": 1
}
}
}

View File

@@ -40,7 +40,7 @@ services:
fluentd-buffer-limit: '52428800'
tag: parr.next-run-rabbit.serilog
deploy:
replicas: 1
replicas: 4
networks:
- parr-network