diff --git a/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php b/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php index 62aaea5..e7db19e 100644 --- a/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php +++ b/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php @@ -22,9 +22,18 @@ class DateIntervalFilter implements TypeFilter */ public function apply(mixed $element) { + $properties = get_object_vars($element); + + // Since PHP 8.2 an interval from createFromDateString() exposes + // "from_string"/"date_string" instead of y/m/d/h/i/s, and "from_string" is + // ignored on assignment, so copying property by property would zero it. + if (!empty($properties['from_string'])) { + return DateInterval::createFromDateString($properties['date_string']); + } + $copy = new DateInterval('P0D'); - foreach ($element as $propertyName => $propertyValue) { + foreach ($properties as $propertyName => $propertyValue) { $copy->{$propertyName} = $propertyValue; } diff --git a/tests/DeepCopyTest/TypeFilter/Date/DateIntervalFilterTest.php b/tests/DeepCopyTest/TypeFilter/Date/DateIntervalFilterTest.php index 9552f56..6f95607 100644 --- a/tests/DeepCopyTest/TypeFilter/Date/DateIntervalFilterTest.php +++ b/tests/DeepCopyTest/TypeFilter/Date/DateIntervalFilterTest.php @@ -3,6 +3,7 @@ namespace DeepCopyTest\TypeFilter\Date; use DateInterval; +use DateTimeImmutable; use DeepCopy\TypeFilter\Date\DateIntervalFilter; use PHPUnit\Framework\TestCase; @@ -22,4 +23,45 @@ class DateIntervalFilterTest extends TestCase $this->assertEquals($object, $copy); $this->assertNotSame($object, $copy); } + + public function test_it_deep_copies_a_DateInterval_created_from_a_date_string() + { + $object = DateInterval::createFromDateString('2 days'); + + $filter = new DateIntervalFilter(); + + $copy = $filter->apply($object); + + // The copy has to shift a date by the same amount as the original. + $base = new DateTimeImmutable('2026-01-01 00:00:00'); + + $this->assertSame( + $base->add($object)->format('Y-m-d H:i:s'), + $base->add($copy)->format('Y-m-d H:i:s') + ); + + $this->assertEquals($object, $copy); + $this->assertNotSame($object, $copy); + } + + public function test_it_deep_copies_an_inverted_DateInterval_with_microseconds() + { + $object = new DateInterval('PT1S'); + $object->invert = 1; + $object->f = 0.25; + + $filter = new DateIntervalFilter(); + + $copy = $filter->apply($object); + + $this->assertEquals($object, $copy); + $this->assertNotSame($object, $copy); + + $base = new DateTimeImmutable('2026-01-01 00:00:00'); + + $this->assertSame( + $base->add($object)->format('Y-m-d H:i:s.u'), + $base->add($copy)->format('Y-m-d H:i:s.u') + ); + } }