Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix timezone issue when add/sub with overflow #3074

Merged
merged 4 commits into from
Oct 9, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Allow 1-hour shift if offset changed during the day
kylekatarnls committed Oct 8, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 37a7dd441ce2b0649bc9c333c1197e684f430631
2 changes: 1 addition & 1 deletion src/Carbon/Traits/Date.php
Original file line number Diff line number Diff line change
@@ -2967,6 +2967,6 @@ private function mutateIfMutable(CarbonInterface $date): CarbonInterface
{
return $this instanceof DateTimeImmutable
? $this
: $this->modify('@' . $date->rawFormat('U.u'))->setTimezone($date->getTimezone());
: $this->modify('@'.$date->rawFormat('U.u'))->setTimezone($date->getTimezone());
}
}
98 changes: 88 additions & 10 deletions tests/Carbon/SettersTest.php
Original file line number Diff line number Diff line change
@@ -658,7 +658,7 @@
'microsecond' => 1000000,
];
$valueUnit = array_keys($units)[mt_rand(0, \count($units) - 1)];
$value = mt_rand() > 0.5 ?
$value = mt_rand(0, 1) === 1 ?
mt_rand(-9999, 9999) :
mt_rand(-60, 60);

@@ -803,7 +803,7 @@
'microsecond' => 1000000,
];
$valueUnit = array_keys($units)[mt_rand(0, \count($units) - 1)];
$value = mt_rand() > 0.5 ?
$value = mt_rand(0, 1) === 1 ?
mt_rand(-9999, 9999) :
mt_rand(-60, 60);

@@ -840,8 +840,7 @@
}
if ($value === $date->$valueUnit ||
$modulo === $date->$valueUnit ||
(method_exists($date, "diffInReal$unit") && -$date->{"diffInReal$unit"}($original, false) === $value) ||
-((int) round($date->{"diffIn$unit"}($original, false))) === $value
(method_exists($date, "diffInReal$unit") && -$date->{"diffInReal$unit"}($original, false) === $value)
) {
$results['current']++;

@@ -860,6 +859,33 @@
continue;
}

$currentDiff = -((int) round($date->{"diffIn$unit"}($original, false)));

if ($currentDiff === $value) {
$results['current']++;

continue;
}

$delta = ($currentDiff - $value);

if ($valueUnit === 'hour') {
$diff = $this->getOffsetChangeOfTheDay($date) ?: $this->getOffsetChangeOfTheDay($original);

if ($diff !== 0) {
$sign = $diff < 0 ? -1 : 1;
$diff = abs($diff);
$minutes = $diff % 100;
$hours = (int) ($sign * (floor($diff / 100) + $minutes / 60));

if ($delta === -$hours) {
$results['current']++;

continue;
}
}
}

$this->failOperation(
$original,
$date,
@@ -912,7 +938,7 @@
'microsecond' => 1000000,
];
$valueUnit = array_keys($units)[mt_rand(0, \count($units) - 1)];
$value = mt_rand() > 0.5 ?
$value = mt_rand(0, 1) === 1 ?
mt_rand(-9999, 9999) :
mt_rand(-60, 60);

@@ -951,8 +977,7 @@

if ($value === $date->$valueUnit ||
$modulo === $date->$valueUnit ||
(method_exists($date, "diffInReal$unit") && $value === $date->{"diffInReal$unit"}($original, false)) ||
((int) round($date->{"diffIn$unit"}($original, false))) === $value
(method_exists($date, "diffInReal$unit") && $value === $date->{"diffInReal$unit"}($original, false))
) {
$results['current']++;

@@ -986,6 +1011,33 @@
continue;
}

$currentDiff = (int) round($date->{"diffIn$unit"}($original, false));

if ($currentDiff === $value) {
$results['current']++;

continue;
}

$delta = ($currentDiff - $value);

if ($valueUnit === 'hour') {
$diff = $this->getOffsetChangeOfTheDay($date) ?: $this->getOffsetChangeOfTheDay($original);

if ($diff !== 0) {
$sign = $diff < 0 ? -1 : 1;
$diff = abs($diff);
$minutes = $diff % 100;
$hours = (int) ($sign * (floor($diff / 100) + $minutes / 60));

if ($delta === $hours) {
$results['current']++;

continue;
}
}
}

$this->failOperation(
$original,
$date,
@@ -998,6 +1050,8 @@
$unit,
$modulo,
$value,
$hours ?? null,
$delta ?? null,

Check failure on line 1054 in tests/Carbon/SettersTest.php

GitHub Actions / PHPStan (8.3)

Variable $delta on left side of ?? always exists and is not nullable.
);
}

@@ -1011,13 +1065,32 @@

public function testOverflowInDst()
{
$date = Carbon::create(2335, 11, 3, 1, 30, 50.138159);
$date->subUnitNoOverflow('year', 5668, 'second');
$date = Carbon::create(2335, 11, 3, 1, 30, 50.138159)
->subUnitNoOverflow('year', 5668, 'second');

$this->assertSame(
'2335-11-03 01:30:50.000000 America/Toronto -0400',
$date->format('Y-m-d H:i:s.u e O'),
);

$date = Carbon::parse('2020-10-15 03:22:57.442989', 'America/Toronto')->hours(-5302);

$diff = (int) ($date->copy()->startOfDay()->format('O') - $date->copy()->endOfDay()->format('O'));
$sign = $diff < 0 ? -1 : 1;
$diff = abs($diff);
$minutes = $diff % 100;
$hours = $sign * (floor($diff / 100) + $minutes / 60);

$diffInHours = $date->diffInHours(
Carbon::parse('2020-10-15 03:22:57.442989', 'America/Toronto'),
);

$this->assertSame(5305.0 + $hours, $diffInHours);
}

private function getOffsetChangeOfTheDay(Carbon $date): int
{
return (int) ($date->copy()->startOfDay()->format('O') - $date->copy()->endOfDay()->format('O'));
}

/**
@@ -1034,7 +1107,9 @@
string $overflowUnit,
string $unit,
int $modulo,
int $variableValue
int $variableValue,
?int $hours = null,
?int $delta = null,
): void {
throw new Exception(implode("\n", [
'Unhandled result for: '.
@@ -1049,6 +1124,9 @@
'Nor '.$end->$valueUnit." (from $end)",
"Nor $value (from value)",
"Nor $modulo (from modulo)",
...($hours !== null ? [
"Not matching diff (hours = $hours vs delta = " . ($delta ?? 'null') . ')',
] : []),
method_exists($date, "diffInReal$unit")
? "diffInReal$unit() exists and returns ".$date->{"diffInReal$unit"}($original, false)
." while expecting $variableValue"