'daily', 'schedule_interval' => 1, 'timezone' => 'UTC', 'schedule_time' => '12:00', ]; $reference = new \DateTimeImmutable('2026-02-22 10:30:00', new \DateTimeZone('UTC')); $next = $calculator->calculateNextRunUtc($job, $reference); $this->assertInstanceOf(\DateTimeImmutable::class, $next); $this->assertSame('2026-02-22 12:00:00', $next->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s')); } public function testCalculateNextRunUtcDailyMovesToNextDayWhenTimeAlreadyPassed(): void { $calculator = new ScheduleCalculator(); $job = [ 'schedule_type' => 'daily', 'schedule_interval' => 1, 'timezone' => 'UTC', 'schedule_time' => '08:00', ]; $reference = new \DateTimeImmutable('2026-02-22 10:30:00', new \DateTimeZone('UTC')); $next = $calculator->calculateNextRunUtc($job, $reference); $this->assertInstanceOf(\DateTimeImmutable::class, $next); $this->assertSame('2026-02-23 08:00:00', $next->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s')); } public function testNormalizeWeekdaysCsvRemovesDuplicatesAndInvalidValues(): void { $calculator = new ScheduleCalculator(); $normalized = $calculator->normalizeWeekdaysCsv(['7', '3', '3', '9', '0', '1']); $this->assertSame('1,3,7', $normalized); } }