fix(dal): EsppScheduleTransformService на входе делаем смещение в зону МСК, чтобы для шаблонов, у которых расписание считается по дням недели и время старта установлено в промежутке 21-0 гринвича, в которое ещё вчера относительно нормальных часовых поясов, расчёт проходит неверно
This commit is contained in:
@@ -7,11 +7,14 @@
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Это текущий день относительно часовой зоны МСК? Да - текущий, нет - следующий день.
|
/// Это текущий день относительно часовой зоны МСК? Да - текущий, нет - следующий день.
|
||||||
|
/// Так делаьб фуфуфу!!!
|
||||||
|
/// смотри IsCurrentDayRelativeMskTime(int hour)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="date">Дата ЮТС</param>
|
/// <param name="date">Дата ЮТС</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool IsCurrentDayRelativeMskTime(DateTimeOffset date)
|
public static bool IsCurrentDayRelativeMskTime(DateTimeOffset date)
|
||||||
{
|
{
|
||||||
|
// смотри IsCurrentDayRelativeMskTime(int hour)
|
||||||
return IsCurrentDayRelativeMskTime(date.Hour);
|
return IsCurrentDayRelativeMskTime(date.Hour);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,6 +28,9 @@
|
|||||||
{
|
{
|
||||||
//Так как в базе всё храним в UTC то время с 21 часа уже соответствует следующими суткам в календаре Москвы
|
//Так как в базе всё храним в UTC то время с 21 часа уже соответствует следующими суткам в календаре Москвы
|
||||||
|
|
||||||
|
//TODO: Не надо так делать!!! НИКАДА!!!
|
||||||
|
// нужно добавить к таймзоне ЮТС +3 часа, посчитать в МСК и потом обратно отнять 3 часа
|
||||||
|
|
||||||
if (hour >= 21)
|
if (hour >= 21)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ namespace PARR.DAL.Tests.TransformServices
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetNextDate_Monthly2_ReturnsSameDateForAllReferenceDates()
|
public async Task GetNextDate_Monthly2_ReturnsSameDateForAllReferenceDates()
|
||||||
{
|
{
|
||||||
@@ -95,7 +96,7 @@ namespace PARR.DAL.Tests.TransformServices
|
|||||||
esppSchTypeConfigServiceMock
|
esppSchTypeConfigServiceMock
|
||||||
.Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny<Guid>()))
|
.Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny<Guid>()))
|
||||||
.ReturnsAsync(scheduleDto);
|
.ReturnsAsync(scheduleDto);
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate);
|
var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate);
|
||||||
var resultFromFutureNonMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureNonMatchingDate);
|
var resultFromFutureNonMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureNonMatchingDate);
|
||||||
@@ -107,6 +108,7 @@ namespace PARR.DAL.Tests.TransformServices
|
|||||||
Assert.Equal(expectedDate, resultFromFutureMatching);
|
Assert.Equal(expectedDate, resultFromFutureMatching);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetNextDate_Monthly_ReturnsSameDateForAllReferenceDates()
|
public async Task GetNextDate_Monthly_ReturnsSameDateForAllReferenceDates()
|
||||||
{
|
{
|
||||||
@@ -161,6 +163,7 @@ namespace PARR.DAL.Tests.TransformServices
|
|||||||
Assert.Equal(expectedDate, resultFromFutureMatching);
|
Assert.Equal(expectedDate, resultFromFutureMatching);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetNextDate_Annually_ReturnsSameDateForAllReferenceDates()
|
public async Task GetNextDate_Annually_ReturnsSameDateForAllReferenceDates()
|
||||||
{
|
{
|
||||||
@@ -236,6 +239,7 @@ namespace PARR.DAL.Tests.TransformServices
|
|||||||
Assert.Equal(expectedDate, resultFromFutureMatching);
|
Assert.Equal(expectedDate, resultFromFutureMatching);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetNextDate_Annually2_ReturnsSameDateForAllReferenceDates()
|
public async Task GetNextDate_Annually2_ReturnsSameDateForAllReferenceDates()
|
||||||
{
|
{
|
||||||
@@ -392,9 +396,9 @@ namespace PARR.DAL.Tests.TransformServices
|
|||||||
public async Task GetNextDate_Regularly_EveryDay()
|
public async Task GetNextDate_Regularly_EveryDay()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var pastDate = new DateTimeOffset(2025, 11, 20, 10, 0, 0, TimeSpan.Zero); // Прошлое время
|
var pastDate = new DateTimeOffset(2025, 11, 20, 20, 0, 0, TimeSpan.Zero); // Прошлое время
|
||||||
var futureDate = new DateTimeOffset(2025, 11, 30, 10, 0, 0, TimeSpan.Zero); // Будущее время
|
var futureDate = new DateTimeOffset(2025, 11, 30, 10, 0, 0, TimeSpan.Zero); // Будущее время
|
||||||
var matchingDate = new DateTimeOffset(2025, 11, 27, 10, 0, 0, TimeSpan.Zero); // Совпадает время
|
var matchingDate = DateTimeOffset.UtcNow; // Совпадает время
|
||||||
|
|
||||||
var scheduleDto = new EsppScheduleDto
|
var scheduleDto = new EsppScheduleDto
|
||||||
{
|
{
|
||||||
@@ -434,25 +438,85 @@ namespace PARR.DAL.Tests.TransformServices
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate);
|
var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate);
|
||||||
var resultFromFutureMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureDate);
|
var resultFromFuture = await service.GetNextDateAsync(Guid.NewGuid(), futureDate);
|
||||||
var resultFromSimpleMatching = await service.GetNextDateAsync(Guid.NewGuid(), matchingDate);
|
var resultFromMatching = await service.GetNextDateAsync(Guid.NewGuid(), matchingDate);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(matchingDate, resultFromPast);
|
Assert.Equal(new DateTimeOffset(
|
||||||
Assert.Equal(futureDate, resultFromFutureMatching);
|
DateTimeOffset.UtcNow.Year,
|
||||||
Assert.Equal(matchingDate, resultFromSimpleMatching);
|
DateTimeOffset.UtcNow.Month,
|
||||||
|
DateTimeOffset.UtcNow.Day,
|
||||||
|
20, 0, 0, 0, 0, TimeSpan.Zero), resultFromPast);
|
||||||
|
Assert.Equal(futureDate, resultFromFuture);
|
||||||
|
Assert.Equal(matchingDate.AddDays(1), resultFromMatching);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
/// <summary>
|
|
||||||
/// дата в будущем, но не по расписанию
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetNextDate_Weekly_FutureDateNotMatchingSchedule_ReturnsNextScheduledDate()
|
public async Task GetNextDate_Regularly_Every3Year()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var futureDate = new DateTimeOffset(2025, 12, 04, 10, 0, 0, TimeSpan.Zero); // Четверг
|
var pastDate = new DateTimeOffset(2020, 11, 20, 10, 0, 0, TimeSpan.Zero); // Прошлое время
|
||||||
|
var futureDate = new DateTimeOffset(2026, 11, 30, 10, 0, 0, TimeSpan.Zero); // Будущее время
|
||||||
|
var matchingDate = DateTimeOffset.UtcNow; // Совпадает время
|
||||||
|
var failureDate = new DateTimeOffset(2027, 01, 01, 23, 59, 0, TimeSpan.Zero); // Дата с ошибкой в работе
|
||||||
|
|
||||||
|
var scheduleDto = new EsppScheduleDto
|
||||||
|
{
|
||||||
|
TypeSchedule = new EsppSchTypeSchedule
|
||||||
|
{
|
||||||
|
Id = (int)EsppSchTypeScheduleEnum.Regularly,
|
||||||
|
Name = "Regularly",
|
||||||
|
Description = "Регулярно"
|
||||||
|
},
|
||||||
|
Values = new List<EsppScheduleValDto>
|
||||||
|
{
|
||||||
|
new EsppScheduleValDto
|
||||||
|
{
|
||||||
|
Order = 1,
|
||||||
|
Type = new EsppSchType
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Name = "Интервал",
|
||||||
|
Description = "Интервал повторения (например, Ежедневно)"
|
||||||
|
},
|
||||||
|
Value = new EsppSchTypeValue
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Value = "Каждые 3 года",
|
||||||
|
EsppExportValue = "1095 00:00:00",
|
||||||
|
TypeId = 1,
|
||||||
|
DateCreated = DateTimeOffset.UtcNow,
|
||||||
|
Order = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
esppSchTypeConfigServiceMock
|
||||||
|
.Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny<Guid>()))
|
||||||
|
.ReturnsAsync(scheduleDto);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate);
|
||||||
|
var resultFromFutureMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureDate);
|
||||||
|
var resultFromSimpleMatching = await service.GetNextDateAsync(Guid.NewGuid(), matchingDate);
|
||||||
|
var resultFromFailure = await service.GetNextDateAsync(Guid.NewGuid(), failureDate);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(pastDate.AddHours(26280 * 2), resultFromPast);
|
||||||
|
Assert.Equal(futureDate, resultFromFutureMatching);
|
||||||
|
Assert.Equal(matchingDate.AddHours(26280), resultFromSimpleMatching);
|
||||||
|
Assert.Equal(failureDate, resultFromFailure);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetNextDate_Weekly_TestUTCToMsk()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var beforeMSKTZ = new DateTimeOffset(2025, 11, 25, 3, 0, 0, TimeSpan.Zero);
|
||||||
|
var afterMSKTZ = new DateTimeOffset(2025, 12, 01, 3, 0, 0, TimeSpan.Zero);
|
||||||
|
|
||||||
var scheduleDto = new EsppScheduleDto
|
var scheduleDto = new EsppScheduleDto
|
||||||
{
|
{
|
||||||
@@ -491,124 +555,12 @@ namespace PARR.DAL.Tests.TransformServices
|
|||||||
.ReturnsAsync(scheduleDto);
|
.ReturnsAsync(scheduleDto);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = await service.GetNextDateAsync(Guid.NewGuid(), futureDate);
|
var resultFrombeforeMSKTZ = await service.GetNextDateAsync(Guid.NewGuid(), beforeMSKTZ);
|
||||||
|
var resultFromafterMSKTZ = await service.GetNextDateAsync(Guid.NewGuid(), afterMSKTZ);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(DayOfWeek.Monday, result.DayOfWeek);
|
Assert.Equal(new DateTimeOffset(2025, 12, 1, 3, 0, 0, TimeSpan.Zero), resultFrombeforeMSKTZ);
|
||||||
Assert.True(result >= DateTimeOffset.UtcNow, "Дата должна быть в будущем");
|
Assert.Equal(new DateTimeOffset(2025, 12, 1, 3, 0, 0, TimeSpan.Zero), resultFromafterMSKTZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// несуществующая дата (31 февраля)
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[Fact]
|
|
||||||
public async Task GetNextDate_Monthly_InvalidDay_FallsBackToLastDay()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var pastDate = new DateTimeOffset(2025, 1, 10, 10, 0, 0, TimeSpan.Zero); // Прошлое
|
|
||||||
|
|
||||||
var scheduleDto = new EsppScheduleDto
|
|
||||||
{
|
|
||||||
TypeSchedule = new EsppSchTypeSchedule
|
|
||||||
{
|
|
||||||
Id = (int)EsppSchTypeScheduleEnum.Monthly,
|
|
||||||
Name = "Ежемесячно",
|
|
||||||
Description = "Расписание по числу месяца"
|
|
||||||
},
|
|
||||||
Values = new List<EsppScheduleValDto>
|
|
||||||
{
|
|
||||||
new EsppScheduleValDto
|
|
||||||
{
|
|
||||||
Order = 1,
|
|
||||||
Type = new EsppSchType
|
|
||||||
{
|
|
||||||
Id = 1,
|
|
||||||
Name = "День месяца",
|
|
||||||
Description = "Число месяца"
|
|
||||||
},
|
|
||||||
Value = new EsppSchTypeValue
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Value = "31", // <-- 31 февраля не существует
|
|
||||||
EsppExportValue = "31-е число",
|
|
||||||
TypeId = 1,
|
|
||||||
DateCreated = DateTimeOffset.UtcNow,
|
|
||||||
Order = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
esppSchTypeConfigServiceMock
|
|
||||||
.Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny<Guid>()))
|
|
||||||
.ReturnsAsync(scheduleDto);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = await service.GetNextDateAsync(Guid.NewGuid(), pastDate);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
// Результат должен быть 28 февраля (или 29 в високосный год)
|
|
||||||
Assert.Equal(28, result.Day); // или 29, если високосный
|
|
||||||
Assert.Equal(2, result.Month);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// корректная рекурсия (без зацикливания)
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[Fact]
|
|
||||||
public async Task GetNextDate_Regularly_RecursionDoesNotLoop()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var pastDate = new DateTimeOffset(1925, 11, 20, 10, 0, 0, TimeSpan.Zero); // Давно прошло
|
|
||||||
|
|
||||||
var scheduleDto = new EsppScheduleDto
|
|
||||||
{
|
|
||||||
TypeSchedule = new EsppSchTypeSchedule
|
|
||||||
{
|
|
||||||
Id = (int)EsppSchTypeScheduleEnum.Regularly,
|
|
||||||
Name = "Регулярно",
|
|
||||||
Description = "Регулярное расписание"
|
|
||||||
},
|
|
||||||
Values = new List<EsppScheduleValDto>
|
|
||||||
{
|
|
||||||
new EsppScheduleValDto
|
|
||||||
{
|
|
||||||
Order = 1,
|
|
||||||
Type = new EsppSchType
|
|
||||||
{
|
|
||||||
Id = 1,
|
|
||||||
Name = "Интервал",
|
|
||||||
Description = "Интервал повторения (например, Ежедневно)"
|
|
||||||
},
|
|
||||||
Value = new EsppSchTypeValue
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Value = "Каждые 2 часа", // <-- Интервал 2 часа
|
|
||||||
EsppExportValue = "Каждые 2 часа",
|
|
||||||
TypeId = 1,
|
|
||||||
DateCreated = DateTimeOffset.UtcNow,
|
|
||||||
Order = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
esppSchTypeConfigServiceMock
|
|
||||||
.Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny<Guid>()))
|
|
||||||
.ReturnsAsync(scheduleDto);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = await service.GetNextDateAsync(Guid.NewGuid(), pastDate);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
// Результат должен быть >= DateTimeOffset.UtcNow
|
|
||||||
Assert.True(result >= DateTimeOffset.UtcNow, "Дата должна быть в будущем");
|
|
||||||
// Должно быть кратно интервалу
|
|
||||||
var diff = (result - pastDate).TotalHours;
|
|
||||||
Assert.True(diff % 2 == 0 || diff % 2 == 2, "Разница должна быть кратна 2 часам");
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using PARR.Common;
|
|
||||||
using PARR.Constants;
|
using PARR.Constants;
|
||||||
using PARR.DAL.Contracts;
|
using PARR.DAL.Contracts;
|
||||||
using PARR.DAL.DomainModels;
|
using PARR.DAL.DomainModels;
|
||||||
@@ -73,33 +72,40 @@ namespace PARR.DAL.TransformServices
|
|||||||
{
|
{
|
||||||
var nextRun = referenceDate;
|
var nextRun = referenceDate;
|
||||||
|
|
||||||
|
//---------
|
||||||
|
// Для рассчета по МСК времени, потому что в ЮТС может быть еще ВСК, а по МСК это уже ПНД
|
||||||
|
var offsetReferenceDate = referenceDate.ToOffset(new TimeSpan(3, 0, 0));
|
||||||
|
//---------
|
||||||
|
|
||||||
switch (esppSchedule.TypeSchedule.Id)
|
switch (esppSchedule.TypeSchedule.Id)
|
||||||
{
|
{
|
||||||
case (int)EsppSchTypeScheduleEnum.Regularly:
|
case (int)EsppSchTypeScheduleEnum.Regularly:
|
||||||
nextRun = GetNextDateRegularly(esppSchedule.Values, referenceDate);
|
nextRun = GetNextDateRegularly(esppSchedule.Values, offsetReferenceDate);
|
||||||
break;
|
break;
|
||||||
case (int)EsppSchTypeScheduleEnum.Weekly:
|
case (int)EsppSchTypeScheduleEnum.Weekly:
|
||||||
nextRun = GetNextDateWeekly(esppSchedule.Values, referenceDate);
|
nextRun = GetNextDateWeekly(esppSchedule.Values, offsetReferenceDate);
|
||||||
break;
|
break;
|
||||||
case (int)EsppSchTypeScheduleEnum.Monthly:
|
case (int)EsppSchTypeScheduleEnum.Monthly:
|
||||||
nextRun = GetNextDateMonthly(esppSchedule.Values, referenceDate);
|
nextRun = GetNextDateMonthly(esppSchedule.Values, offsetReferenceDate);
|
||||||
break;
|
break;
|
||||||
case (int)EsppSchTypeScheduleEnum.Monthly2:
|
case (int)EsppSchTypeScheduleEnum.Monthly2:
|
||||||
nextRun = GetNextDateMonthly2(esppSchedule.Values, referenceDate);
|
nextRun = GetNextDateMonthly2(esppSchedule.Values, offsetReferenceDate);
|
||||||
break;
|
break;
|
||||||
case (int)EsppSchTypeScheduleEnum.Annually:
|
case (int)EsppSchTypeScheduleEnum.Annually:
|
||||||
nextRun = GetNextDateAnnually(esppSchedule.Values, referenceDate);
|
nextRun = GetNextDateAnnually(esppSchedule.Values, offsetReferenceDate);
|
||||||
break;
|
break;
|
||||||
case (int)EsppSchTypeScheduleEnum.Annually2:
|
case (int)EsppSchTypeScheduleEnum.Annually2:
|
||||||
nextRun = GetNextDateAnnually2(esppSchedule.Values, referenceDate);
|
nextRun = GetNextDateAnnually2(esppSchedule.Values, offsetReferenceDate);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Возвращаем обратно в ЮТС
|
||||||
|
nextRun = nextRun.ToOffset(TimeSpan.Zero);
|
||||||
//возможно для автораспределения нужно nextRun = nextRunModifierService.GetWorkDayAsync(nextRun).GetAwaiter().GetResult();
|
//возможно для автораспределения нужно nextRun = nextRunModifierService.GetWorkDayAsync(nextRun).GetAwaiter().GetResult();
|
||||||
|
|
||||||
// тут может быть 21 час по МСК, то это предыдущие сутки, нужно отнять 1 день
|
// тут может быть 21 час по МСК, то это предыдущие сутки, нужно отнять 1 день
|
||||||
if (!DateResolver.IsCurrentDayRelativeMskTime(nextRun.Hour))
|
//if (!DateResolver.IsCurrentDayRelativeMskTime(nextRun.Hour))
|
||||||
nextRun = nextRun.AddDays(-1);
|
// nextRun = nextRun.AddDays(-1);
|
||||||
|
|
||||||
return nextRun;
|
return nextRun;
|
||||||
}
|
}
|
||||||
@@ -196,7 +202,7 @@ namespace PARR.DAL.TransformServices
|
|||||||
{"Каждые 1,5 года", 13140},
|
{"Каждые 1,5 года", 13140},
|
||||||
{"Каждые 3 года", 26280},
|
{"Каждые 3 года", 26280},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
if (!regDict.TryGetValue(values[0].Value.Value, out int regNum))
|
if (!regDict.TryGetValue(values[0].Value.Value, out int regNum))
|
||||||
@@ -206,8 +212,6 @@ namespace PARR.DAL.TransformServices
|
|||||||
}
|
}
|
||||||
|
|
||||||
var calcDay = referenceDate;
|
var calcDay = referenceDate;
|
||||||
if (calcDay < DateTimeOffset.UtcNow)
|
|
||||||
calcDay = calcDay.AddHours(regNum);
|
|
||||||
|
|
||||||
//TODO: вот это повторяется от метода к методу
|
//TODO: вот это повторяется от метода к методу
|
||||||
//Если итоговая дата указывает на прошлое, то повторяем расчёт и уходим в рекурсию
|
//Если итоговая дата указывает на прошлое, то повторяем расчёт и уходим в рекурсию
|
||||||
|
|||||||
Reference in New Issue
Block a user