fix: keep intervals built by createFromDateString() when deep copying

Since PHP 8.2 a DateInterval created by DateInterval::createFromDateString()
exposes only "from_string" and "date_string" instead of the y/m/d/h/i/s
fields, and "from_string" is ignored when assigned to. Rebuilding such an
interval by copying its visible properties onto a new DateInterval therefore
produced a zero interval, so a copied interval silently stopped shifting
dates.

Read the properties once and rebuild a date-string interval from the string
it was created from, leaving the existing property copy for every other
interval. Cloning would also fix it but would invoke __clone() on userland
DateInterval subclasses, which #76 explicitly rules out.
This commit is contained in:
dualfroz committed 2026-09-06 00:57:12 +02:00
1 parent 0ea3878598
commit e6d94fc32a
2 files changed
+52 -1

No files matched your search

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