Skip to content

Commit

Permalink
Allow 1-hour shift if offset changed during the day
Browse files Browse the repository at this point in the history
  • Loading branch information
kylekatarnls committed Oct 8, 2024
1 parent 599606d commit 0548c6e
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/Carbon/Traits/Date.php
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}
68 changes: 60 additions & 8 deletions tests/Carbon/SettersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ public function testSetUnitNoOverflow()
'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);

Expand Down Expand Up @@ -803,7 +803,7 @@ public function testAddUnitNoOverflow()
'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);

Expand Down Expand Up @@ -912,7 +912,7 @@ public function testSubUnitNoOverflow()
'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);

Expand Down Expand Up @@ -951,8 +951,7 @@ public function testSubUnitNoOverflow()

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']++;

Expand Down Expand Up @@ -986,6 +985,33 @@ public function testSubUnitNoOverflow()
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,
Expand All @@ -998,6 +1024,8 @@ public function testSubUnitNoOverflow()
$unit,
$modulo,
$value,
$hours ?? null,
$delta ?? null,

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

View workflow job for this annotation

GitHub Actions / PHPStan (8.3)

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

Expand All @@ -1011,13 +1039,32 @@ public function testSubUnitNoOverflow()

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'));
}

/**
Expand All @@ -1034,7 +1081,9 @@ private function failOperation(
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: '.
Expand All @@ -1049,6 +1098,9 @@ private function failOperation(
'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"
Expand Down

0 comments on commit 0548c6e

Please sign in to comment.