diff --git a/src/Symfony/Component/Scheduler/CHANGELOG.md b/src/Symfony/Component/Scheduler/CHANGELOG.md index f5a3d015eac64..a2b7fd057ed1d 100644 --- a/src/Symfony/Component/Scheduler/CHANGELOG.md +++ b/src/Symfony/Component/Scheduler/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +6.4 +--- + + * Allow setting timezone of next run date in CronExpressionTrigger + 6.3 --- diff --git a/src/Symfony/Component/Scheduler/RecurringMessage.php b/src/Symfony/Component/Scheduler/RecurringMessage.php index ed0badb8503d2..d99ec2eb16953 100644 --- a/src/Symfony/Component/Scheduler/RecurringMessage.php +++ b/src/Symfony/Component/Scheduler/RecurringMessage.php @@ -48,17 +48,17 @@ public static function every(string|int|\DateInterval $frequency, object $messag return new self(new PeriodicalTrigger($frequency, $from, $until), $message); } - public static function cron(string $expression, object $message): self + public static function cron(string $expression, object $message, \DateTimeZone|string $timezone = null): self { if (!str_contains($expression, '#')) { - return new self(CronExpressionTrigger::fromSpec($expression), $message); + return new self(CronExpressionTrigger::fromSpec($expression, null, $timezone), $message); } if (!$message instanceof \Stringable) { throw new InvalidArgumentException('A message must be stringable to use "hashed" cron expressions.'); } - return new self(CronExpressionTrigger::fromSpec($expression, (string) $message), $message); + return new self(CronExpressionTrigger::fromSpec($expression, (string) $message, $timezone), $message); } public static function trigger(TriggerInterface $trigger, object $message): self diff --git a/src/Symfony/Component/Scheduler/Tests/Trigger/CronExpressionTriggerTest.php b/src/Symfony/Component/Scheduler/Tests/Trigger/CronExpressionTriggerTest.php index db21020c61e0b..cf12a7ceccf52 100644 --- a/src/Symfony/Component/Scheduler/Tests/Trigger/CronExpressionTriggerTest.php +++ b/src/Symfony/Component/Scheduler/Tests/Trigger/CronExpressionTriggerTest.php @@ -96,4 +96,19 @@ public function testFromHashWithStandardExpression() $this->assertSame('56 20 1 9 0', (string) CronExpressionTrigger::fromSpec('56 20 1 9 0', 'some context')); $this->assertSame('0 0 * * *', (string) CronExpressionTrigger::fromSpec('@daily')); } + + public function testDefaultTimezone() + { + $now = new \DateTimeImmutable('Europe/Paris'); + $trigger = CronExpressionTrigger::fromSpec('0 12 * * *'); + $this->assertSame('Europe/Paris', $trigger->getNextRunDate($now)->getTimezone()->getName()); + } + + public function testTimezoneIsUsed() + { + $now = new \DateTimeImmutable('Europe/Paris'); + $timezone = new \DateTimeZone('UTC'); + $trigger = CronExpressionTrigger::fromSpec('0 12 * * *', null, $timezone); + $this->assertSame('UTC', $trigger->getNextRunDate($now)->getTimezone()->getName()); + } } diff --git a/src/Symfony/Component/Scheduler/Trigger/CronExpressionTrigger.php b/src/Symfony/Component/Scheduler/Trigger/CronExpressionTrigger.php index 169af5b15ee48..20fcc960be367 100644 --- a/src/Symfony/Component/Scheduler/Trigger/CronExpressionTrigger.php +++ b/src/Symfony/Component/Scheduler/Trigger/CronExpressionTrigger.php @@ -46,9 +46,13 @@ final class CronExpressionTrigger implements TriggerInterface [0, 6], ]; + private readonly ?string $timezone; + public function __construct( private readonly CronExpression $expression = new CronExpression('* * * * *'), + \DateTimeZone|string $timezone = null, ) { + $this->timezone = $timezone instanceof \DateTimeZone ? $timezone->getName() : $timezone; } public function __toString(): string @@ -56,26 +60,26 @@ public function __toString(): string return $this->expression->getExpression(); } - public static function fromSpec(string $expression = '* * * * *', string $context = null): self + public static function fromSpec(string $expression = '* * * * *', string $context = null, \DateTimeZone|string $timezone = null): self { if (!class_exists(CronExpression::class)) { throw new LogicException(sprintf('You cannot use "%s" as the "cron expression" package is not installed. Try running "composer require dragonmantank/cron-expression".', __CLASS__)); } if (!str_contains($expression, '#')) { - return new self(new CronExpression($expression)); + return new self(new CronExpression($expression), $timezone); } if (null === $context) { throw new LogicException('A context must be provided to use "hashed" cron expressions.'); } - return new self(new CronExpression(self::parseHashed($expression, $context))); + return new self(new CronExpression(self::parseHashed($expression, $context)), $timezone); } public function getNextRunDate(\DateTimeImmutable $run): ?\DateTimeImmutable { - return \DateTimeImmutable::createFromInterface($this->expression->getNextRunDate($run)); + return \DateTimeImmutable::createFromInterface($this->expression->getNextRunDate($run, timeZone: $this->timezone)); } private static function parseHashed(string $expression, string $context): string
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: