Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c842016

Browse filesBrowse files
committed
[RateLimiter] Fix DateInterval normalization
1 parent 97aedb3 commit c842016
Copy full SHA for c842016

File tree

3 files changed

+40
-2
lines changed
Filter options

3 files changed

+40
-2
lines changed

‎src/Symfony/Component/RateLimiter/RateLimiterFactory.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/RateLimiter/RateLimiterFactory.php
+5-1Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ protected static function configureOptions(OptionsResolver $options): void
6969
{
7070
$intervalNormalizer = static function (Options $options, string $interval): \DateInterval {
7171
try {
72-
return (new \DateTimeImmutable())->diff(new \DateTimeImmutable('+'.$interval));
72+
// Force UTC timezone, because we don't want to deal with quirks happening when modifying dates in case
73+
// there is a default timezone with DST. Read more here https://github.com/symfony/symfony/pull/58757
74+
$now = \DateTimeImmutable::createFromFormat('U', time(), new \DateTimeZone('UTC'));
75+
76+
return $now->diff($now->modify('+'.$interval));
7377
} catch (\Exception $e) {
7478
if (!preg_match('/Failed to parse time string \(\+([^)]+)\)/', $e->getMessage(), $m)) {
7579
throw $e;

‎src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php
+34Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\RateLimiter\Tests;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\ClockMock;
1516
use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
1617
use Symfony\Component\RateLimiter\Policy\FixedWindowLimiter;
1718
use Symfony\Component\RateLimiter\Policy\NoLimiter;
@@ -76,4 +77,37 @@ public static function invalidConfigProvider()
7677
'policy' => 'token_bucket',
7778
]];
7879
}
80+
81+
/**
82+
* @group time-sensitive
83+
*/
84+
public function testExpirationTimeCalculationWhenUsingDefaultTimezoneRomeWithIntervalAfterCETChange()
85+
{
86+
$originalTimezone = date_default_timezone_get();
87+
try {
88+
// Timestamp for 'Sun 27 Oct 2024 12:59:40 AM UTC' that's just 20 seconds before switch CEST->CET
89+
ClockMock::withClockMock(1729990780);
90+
91+
// This is a prerequisite for the bug to happen
92+
date_default_timezone_set('Europe/Rome');
93+
94+
$storage = new InMemoryStorage();
95+
$factory = new RateLimiterFactory(
96+
[
97+
'id' => 'id_1',
98+
'policy' => 'fixed_window',
99+
'limit' => 30,
100+
'interval' => '21 seconds',
101+
],
102+
$storage
103+
);
104+
$rateLimiter = $factory->create('key');
105+
$rateLimiter->consume(1);
106+
$limiterState = $storage->fetch('id_1-key');
107+
// As expected the expiration is equal to the interval we defined
108+
$this->assertSame(21, $limiterState->getExpirationTime());
109+
} finally {
110+
date_default_timezone_set($originalTimezone);
111+
}
112+
}
79113
}

‎src/Symfony/Component/RateLimiter/Util/TimeUtil.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/RateLimiter/Util/TimeUtil.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ final class TimeUtil
2020
{
2121
public static function dateIntervalToSeconds(\DateInterval $interval): int
2222
{
23-
$now = new \DateTimeImmutable();
23+
$now = \DateTimeImmutable::createFromFormat('U', time(), new \DateTimeZone('UTC'));
2424

2525
return $now->add($interval)->getTimestamp() - $now->getTimestamp();
2626
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.