Skip to content

Commit be9ea53

Browse files
feature #50572 [Scheduler] Allow setting cron expression next run date timezone (danielburger1337)
This PR was squashed before being merged into the 6.4 branch. Discussion ---------- [Scheduler] Allow setting cron expression next run date timezone | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | | License | MIT | Doc PR | Allow setting the timezone for the next run date derived from a cron expression. This is my first contribution to an experimental component and therefor I am not familiar with the exact contribution guidelines. As this component is experimental, I think it is ok to submit this PR against branch 6.3, right? Im also not sure about the CHANGELOG.md entry I should make. Would I add this under the 6.3.1 section or where? Commits ------- 35756c1 [Scheduler] Allow setting cron expression next run date timezone
2 parents 30b2b73 + 35756c1 commit be9ea53

File tree

4 files changed

+31
-7
lines changed

4 files changed

+31
-7
lines changed

src/Symfony/Component/Scheduler/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
6.4
5+
---
6+
7+
* Allow setting timezone of next run date in CronExpressionTrigger
8+
49
6.3
510
---
611

src/Symfony/Component/Scheduler/RecurringMessage.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,17 @@ public static function every(string|int|\DateInterval $frequency, object $messag
4848
return new self(new PeriodicalTrigger($frequency, $from, $until), $message);
4949
}
5050

51-
public static function cron(string $expression, object $message): self
51+
public static function cron(string $expression, object $message, \DateTimeZone|string $timezone = null): self
5252
{
5353
if (!str_contains($expression, '#')) {
54-
return new self(CronExpressionTrigger::fromSpec($expression), $message);
54+
return new self(CronExpressionTrigger::fromSpec($expression, null, $timezone), $message);
5555
}
5656

5757
if (!$message instanceof \Stringable) {
5858
throw new InvalidArgumentException('A message must be stringable to use "hashed" cron expressions.');
5959
}
6060

61-
return new self(CronExpressionTrigger::fromSpec($expression, (string) $message), $message);
61+
return new self(CronExpressionTrigger::fromSpec($expression, (string) $message, $timezone), $message);
6262
}
6363

6464
public static function trigger(TriggerInterface $trigger, object $message): self

src/Symfony/Component/Scheduler/Tests/Trigger/CronExpressionTriggerTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,19 @@ public function testFromHashWithStandardExpression()
9696
$this->assertSame('56 20 1 9 0', (string) CronExpressionTrigger::fromSpec('56 20 1 9 0', 'some context'));
9797
$this->assertSame('0 0 * * *', (string) CronExpressionTrigger::fromSpec('@daily'));
9898
}
99+
100+
public function testDefaultTimezone()
101+
{
102+
$now = new \DateTimeImmutable('Europe/Paris');
103+
$trigger = CronExpressionTrigger::fromSpec('0 12 * * *');
104+
$this->assertSame('Europe/Paris', $trigger->getNextRunDate($now)->getTimezone()->getName());
105+
}
106+
107+
public function testTimezoneIsUsed()
108+
{
109+
$now = new \DateTimeImmutable('Europe/Paris');
110+
$timezone = new \DateTimeZone('UTC');
111+
$trigger = CronExpressionTrigger::fromSpec('0 12 * * *', null, $timezone);
112+
$this->assertSame('UTC', $trigger->getNextRunDate($now)->getTimezone()->getName());
113+
}
99114
}

src/Symfony/Component/Scheduler/Trigger/CronExpressionTrigger.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,36 +46,40 @@ final class CronExpressionTrigger implements TriggerInterface
4646
[0, 6],
4747
];
4848

49+
private readonly ?string $timezone;
50+
4951
public function __construct(
5052
private readonly CronExpression $expression = new CronExpression('* * * * *'),
53+
\DateTimeZone|string $timezone = null,
5154
) {
55+
$this->timezone = $timezone instanceof \DateTimeZone ? $timezone->getName() : $timezone;
5256
}
5357

5458
public function __toString(): string
5559
{
5660
return $this->expression->getExpression();
5761
}
5862

59-
public static function fromSpec(string $expression = '* * * * *', string $context = null): self
63+
public static function fromSpec(string $expression = '* * * * *', string $context = null, \DateTimeZone|string $timezone = null): self
6064
{
6165
if (!class_exists(CronExpression::class)) {
6266
throw new LogicException(sprintf('You cannot use "%s" as the "cron expression" package is not installed. Try running "composer require dragonmantank/cron-expression".', __CLASS__));
6367
}
6468

6569
if (!str_contains($expression, '#')) {
66-
return new self(new CronExpression($expression));
70+
return new self(new CronExpression($expression), $timezone);
6771
}
6872

6973
if (null === $context) {
7074
throw new LogicException('A context must be provided to use "hashed" cron expressions.');
7175
}
7276

73-
return new self(new CronExpression(self::parseHashed($expression, $context)));
77+
return new self(new CronExpression(self::parseHashed($expression, $context)), $timezone);
7478
}
7579

7680
public function getNextRunDate(\DateTimeImmutable $run): ?\DateTimeImmutable
7781
{
78-
return \DateTimeImmutable::createFromInterface($this->expression->getNextRunDate($run));
82+
return \DateTimeImmutable::createFromInterface($this->expression->getNextRunDate($run, timeZone: $this->timezone));
7983
}
8084

8185
private static function parseHashed(string $expression, string $context): string

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

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:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy