diff --git a/PARR.Common/DateResolver.cs b/PARR.Common/DateResolver.cs
index 222f3326..a93c38dc 100644
--- a/PARR.Common/DateResolver.cs
+++ b/PARR.Common/DateResolver.cs
@@ -7,11 +7,14 @@
{
///
/// Это текущий день относительно часовой зоны МСК? Да - текущий, нет - следующий день.
+ /// Так делаьб фуфуфу!!!
+ /// смотри IsCurrentDayRelativeMskTime(int hour)
///
/// Дата ЮТС
///
public static bool IsCurrentDayRelativeMskTime(DateTimeOffset date)
{
+ // смотри IsCurrentDayRelativeMskTime(int hour)
return IsCurrentDayRelativeMskTime(date.Hour);
}
@@ -25,6 +28,9 @@
{
//Так как в базе всё храним в UTC то время с 21 часа уже соответствует следующими суткам в календаре Москвы
+ //TODO: Не надо так делать!!! НИКАДА!!!
+ // нужно добавить к таймзоне ЮТС +3 часа, посчитать в МСК и потом обратно отнять 3 часа
+
if (hour >= 21)
return false;
diff --git a/PARR.DAL.Tests/TransformServices/EsppScheduleTransformServiceTests.cs b/PARR.DAL.Tests/TransformServices/EsppScheduleTransformServiceTests.cs
index e720889b..b270167e 100644
--- a/PARR.DAL.Tests/TransformServices/EsppScheduleTransformServiceTests.cs
+++ b/PARR.DAL.Tests/TransformServices/EsppScheduleTransformServiceTests.cs
@@ -32,6 +32,7 @@ namespace PARR.DAL.Tests.TransformServices
);
}
+
[Fact]
public async Task GetNextDate_Monthly2_ReturnsSameDateForAllReferenceDates()
{
@@ -95,7 +96,7 @@ namespace PARR.DAL.Tests.TransformServices
esppSchTypeConfigServiceMock
.Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny()))
.ReturnsAsync(scheduleDto);
-
+
//Act
var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate);
var resultFromFutureNonMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureNonMatchingDate);
@@ -107,6 +108,7 @@ namespace PARR.DAL.Tests.TransformServices
Assert.Equal(expectedDate, resultFromFutureMatching);
}
+
[Fact]
public async Task GetNextDate_Monthly_ReturnsSameDateForAllReferenceDates()
{
@@ -161,6 +163,7 @@ namespace PARR.DAL.Tests.TransformServices
Assert.Equal(expectedDate, resultFromFutureMatching);
}
+
[Fact]
public async Task GetNextDate_Annually_ReturnsSameDateForAllReferenceDates()
{
@@ -236,6 +239,7 @@ namespace PARR.DAL.Tests.TransformServices
Assert.Equal(expectedDate, resultFromFutureMatching);
}
+
[Fact]
public async Task GetNextDate_Annually2_ReturnsSameDateForAllReferenceDates()
{
@@ -392,9 +396,9 @@ namespace PARR.DAL.Tests.TransformServices
public async Task GetNextDate_Regularly_EveryDay()
{
// 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 matchingDate = new DateTimeOffset(2025, 11, 27, 10, 0, 0, TimeSpan.Zero); // Совпадает время
+ var matchingDate = DateTimeOffset.UtcNow; // Совпадает время
var scheduleDto = new EsppScheduleDto
{
@@ -434,25 +438,85 @@ namespace PARR.DAL.Tests.TransformServices
// 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 resultFromFuture = await service.GetNextDateAsync(Guid.NewGuid(), futureDate);
+ var resultFromMatching = await service.GetNextDateAsync(Guid.NewGuid(), matchingDate);
// Assert
- Assert.Equal(matchingDate, resultFromPast);
- Assert.Equal(futureDate, resultFromFutureMatching);
- Assert.Equal(matchingDate, resultFromSimpleMatching);
+ Assert.Equal(new DateTimeOffset(
+ DateTimeOffset.UtcNow.Year,
+ DateTimeOffset.UtcNow.Month,
+ DateTimeOffset.UtcNow.Day,
+ 20, 0, 0, 0, 0, TimeSpan.Zero), resultFromPast);
+ Assert.Equal(futureDate, resultFromFuture);
+ Assert.Equal(matchingDate.AddDays(1), resultFromMatching);
}
- /*
- ///
- /// дата в будущем, но не по расписанию
- ///
- ///
+
[Fact]
- public async Task GetNextDate_Weekly_FutureDateNotMatchingSchedule_ReturnsNextScheduledDate()
+ public async Task GetNextDate_Regularly_Every3Year()
{
// 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
+ {
+ 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()))
+ .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
{
@@ -491,124 +555,12 @@ namespace PARR.DAL.Tests.TransformServices
.ReturnsAsync(scheduleDto);
// 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.Equal(DayOfWeek.Monday, result.DayOfWeek);
- Assert.True(result >= DateTimeOffset.UtcNow, "Дата должна быть в будущем");
+ Assert.Equal(new DateTimeOffset(2025, 12, 1, 3, 0, 0, TimeSpan.Zero), resultFrombeforeMSKTZ);
+ Assert.Equal(new DateTimeOffset(2025, 12, 1, 3, 0, 0, TimeSpan.Zero), resultFromafterMSKTZ);
}
-
- ///
- /// несуществующая дата (31 февраля)
- ///
- ///
- [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
- {
- 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()))
- .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);
- }
-
-
- ///
- /// корректная рекурсия (без зацикливания)
- ///
- ///
- [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
- {
- 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()))
- .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 часам");
- }*/
}
}
diff --git a/PARR.DAL/TransformServices/EsppScheduleTransformService.cs b/PARR.DAL/TransformServices/EsppScheduleTransformService.cs
index 06ed46b6..bdca7091 100644
--- a/PARR.DAL/TransformServices/EsppScheduleTransformService.cs
+++ b/PARR.DAL/TransformServices/EsppScheduleTransformService.cs
@@ -1,5 +1,4 @@
using Microsoft.Extensions.Logging;
-using PARR.Common;
using PARR.Constants;
using PARR.DAL.Contracts;
using PARR.DAL.DomainModels;
@@ -73,33 +72,40 @@ namespace PARR.DAL.TransformServices
{
var nextRun = referenceDate;
+ //---------
+ // Для рассчета по МСК времени, потому что в ЮТС может быть еще ВСК, а по МСК это уже ПНД
+ var offsetReferenceDate = referenceDate.ToOffset(new TimeSpan(3, 0, 0));
+ //---------
+
switch (esppSchedule.TypeSchedule.Id)
{
case (int)EsppSchTypeScheduleEnum.Regularly:
- nextRun = GetNextDateRegularly(esppSchedule.Values, referenceDate);
+ nextRun = GetNextDateRegularly(esppSchedule.Values, offsetReferenceDate);
break;
case (int)EsppSchTypeScheduleEnum.Weekly:
- nextRun = GetNextDateWeekly(esppSchedule.Values, referenceDate);
+ nextRun = GetNextDateWeekly(esppSchedule.Values, offsetReferenceDate);
break;
case (int)EsppSchTypeScheduleEnum.Monthly:
- nextRun = GetNextDateMonthly(esppSchedule.Values, referenceDate);
+ nextRun = GetNextDateMonthly(esppSchedule.Values, offsetReferenceDate);
break;
case (int)EsppSchTypeScheduleEnum.Monthly2:
- nextRun = GetNextDateMonthly2(esppSchedule.Values, referenceDate);
+ nextRun = GetNextDateMonthly2(esppSchedule.Values, offsetReferenceDate);
break;
case (int)EsppSchTypeScheduleEnum.Annually:
- nextRun = GetNextDateAnnually(esppSchedule.Values, referenceDate);
+ nextRun = GetNextDateAnnually(esppSchedule.Values, offsetReferenceDate);
break;
case (int)EsppSchTypeScheduleEnum.Annually2:
- nextRun = GetNextDateAnnually2(esppSchedule.Values, referenceDate);
+ nextRun = GetNextDateAnnually2(esppSchedule.Values, offsetReferenceDate);
break;
}
+ // Возвращаем обратно в ЮТС
+ nextRun = nextRun.ToOffset(TimeSpan.Zero);
//возможно для автораспределения нужно nextRun = nextRunModifierService.GetWorkDayAsync(nextRun).GetAwaiter().GetResult();
// тут может быть 21 час по МСК, то это предыдущие сутки, нужно отнять 1 день
- if (!DateResolver.IsCurrentDayRelativeMskTime(nextRun.Hour))
- nextRun = nextRun.AddDays(-1);
+ //if (!DateResolver.IsCurrentDayRelativeMskTime(nextRun.Hour))
+ // nextRun = nextRun.AddDays(-1);
return nextRun;
}
@@ -196,7 +202,7 @@ namespace PARR.DAL.TransformServices
{"Каждые 1,5 года", 13140},
{"Каждые 3 года", 26280},
- };
+ };
if (!regDict.TryGetValue(values[0].Value.Value, out int regNum))
@@ -206,8 +212,6 @@ namespace PARR.DAL.TransformServices
}
var calcDay = referenceDate;
- if (calcDay < DateTimeOffset.UtcNow)
- calcDay = calcDay.AddHours(regNum);
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и уходим в рекурсию