DateTimeImmutable

← DateTimeImmutable

Ashterix

docs: English JsonRpcBundle docs, REST and MCP Bundle sections, package cards

en/articles/from-tg/series/php-can-do/datetime-immutable.md new file +97 βˆ’0

1 + # DateTimeImmutable
2 +
3 + *When time changes but objects don't*
4 +
5 + - **Added in:** PHP 5.5
6 + - **What it gives you:** a class that behaves like `DateTime`, but doesn't change when modified β€” it returns a cloned object instead.
7 +
8 + ## What it's about
9 +
10 + In PHP, if we change the time of a `DateTime` object, it changes everywhere it has been passed, because objects in PHP are always passed by reference, and this can lead to unexpected behaviour.
11 +
12 + `DateTimeImmutable` solves this problem β€” any operation on a date returns a new instance instead of mutating the old one.
13 +
14 + ## When it really makes sense
15 +
16 + - in DTOs / Value Objects β€” so the time is guaranteed not to change after being passed along;
17 + - in schedulers, timetables, reports β€” when you compute many dates from a base one;
18 + - in business logic β€” when one date is derived from another (start/end of a period, a deadline, a promotion, etc.).
19 +
20 + ## A problem that's easy to miss
21 +
22 + In production code, `DateTime` is often passed between services and DTOs, or cached in containers.
23 +
24 + And here comes the typical story:
25 +
26 + ```php
27 + class Campaign {
28 + public function __construct(
29 + public string $name,
30 + public DateTime $startsAt,
31 + public DateTime $endsAt,
32 + ) {}
33 + }
34 +
35 + $base = new DateTime('2025-10-01');
36 + $campaign = new Campaign(
37 + name: 'Autumn Sale',
38 + startsAt: $base,
39 + endsAt: $base->modify('+7 days')
40 + );
41 +
42 + echo $campaign->startsAt->format('Y-m-d'); // 2025-10-08 ❌
43 + echo $campaign->endsAt->format('Y-m-d'); // 2025-10-08
44 + ```
45 +
46 + We expected the start to be October 1, but `$base` was mutated by `modify`, and as a result the start and the end are the same.
47 +
48 + The same code with `DateTimeImmutable` works correctly:
49 +
50 + ```php
51 + $base = new DateTimeImmutable('2025-10-01');
52 + $campaign = new Campaign(
53 + name: 'Autumn Sale',
54 + startsAt: $base,
55 + endsAt: $base->modify('+7 days')
56 + );
57 +
58 + echo $campaign->startsAt->format('Y-m-d'); // 2025-10-01 βœ…
59 + echo $campaign->endsAt->format('Y-m-d'); // 2025-10-08
60 + ```
61 +
62 + ## One more example
63 +
64 + ```php
65 + class Period {
66 + public function __construct(
67 + public DateTimeImmutable $from,
68 + public DateTimeImmutable $to
69 + ) {}
70 +
71 + public function days(): int {
72 + return $this->to->diff($this->from)->days;
73 + }
74 + }
75 +
76 + $period = new Period(
77 + from: $from = new DateTimeImmutable('2025-06-01'),
78 + to: $from->modify('+10 days'),
79 + );
80 +
81 + echo $period->days(); // 10
82 + ```
83 +
84 + No unexpected mutations β€” the object can be safely cached or passed further.
85 +
86 + ## Conclusion
87 +
88 + > DateTimeImmutable is the safe choice for time-related logic.
89 + > It rules out accidental date changes, where one variable leads to unexpected results.
90 +
91 + If your date can change, sooner or later it will break something in a report, in the logic or in the finances. `Immutable` won't let that happen.
92 +
93 + ← [Previous: Generators](/articles/from-tg/series/php-can-do/generators) Β· [Whole series](/articles/from-tg/series/php-can-do) Β· [Next: Named arguments β†’](/articles/from-tg/series/php-can-do/named-arguments)
94 +
95 + ---
96 +
97 + *First published in Ukrainian in the Telegram channel [β€œCreated to die”](https://t.me/php_while_true/81) on October 21, 2025.*