← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Legacy Date Functions

PHP PHP 5.0+ Intermediate
debt(d5/e3/b5/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list phpstan, rector, and php-cs-fixer — all specialist/configured tools rather than default linters or compilers. The code_pattern confirms these tools can flag date(), mktime(), strtotime() without explicit timezone, but this requires deliberate tooling setup, not out-of-the-box detection.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix describes replacing date() and mktime() with DateTimeImmutable, which is a pattern-level swap. Rector can automate much of this, but strtotime() replacements and clock-mocking in tests add slightly more work than a pure one-liner — landing squarely at e3 rather than e1.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The applies_to covers both web and cli contexts broadly, and the issues (untestable time-dependent code, timezone surprises across the codebase) slow down multiple work streams — testing, i18n, and correctness reviews. Not quite load-bearing architecture (b7), but a persistent tax across many files wherever dates are used.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception directly states that strtotime() is assumed to reliably parse any date string, but it is locale-dependent, ambiguous with formats like '01/02/03', and silently returns false (which becomes timestamp 0). This contradicts reasonable developer expectations derived from similarly-named parsing functions in other languages/libraries, and the silence of the failure (not an exception) makes it a serious trap scoring t7.

About DEBT scoring →

Also Known As

date() strtotime() mktime() legacy date

TL;DR

Using date(), mktime(), strtotime(), and date_create() instead of DateTimeImmutable — the legacy functions are mutable, timezone-unsafe, and cannot be easily mocked.

Explanation

PHP's procedural date functions (date(), mktime(), strtotime()) operate on Unix timestamps and use the default timezone set by date_default_timezone_set(). They are mutable, cannot be mocked in tests, and lead to timezone bugs. DateTimeImmutable (PHP 5.5+) provides an immutable, object-oriented API: timezone-aware, chainable, testable (Carbon extends it), and compatible with DateTimeInterface. date() and strtotime() are acceptable for quick scripts but not for application date logic.

Common Misconception

strtotime() reliably parses any date string — strtotime() is locale-dependent, ambiguous with formats like '01/02/03' (day/month/year or month/day/year?), and silently returns false for unparseable strings.

Why It Matters

Tests that depend on date() return the real current time — untestable. Code using the default timezone breaks when the server timezone is changed. DateTimeImmutable fixes both.

Common Mistakes

  • date('Y-m-d') in tests — untestable; use DateTimeImmutable and mock the clock.
  • strtotime('+1 month') — silently fails on some date strings; use modify('+1 month').
  • Not checking strtotime() for false — invalid input silently becomes timestamp 0 (1970).
  • DateTime (mutable) instead of DateTimeImmutable — shared DateTime references can be modified unexpectedly.

Code Examples

✗ Vulnerable
// Procedural, untestable, timezone-fragile:
$expiry = date('Y-m-d', strtotime('+30 days'));
$timestamp = mktime(0, 0, 0, 12, 25, 2026);
$age = (time() - strtotime($user->birthdate)) / (365.25 * 86400);

// Mutable DateTime — shared reference bug:
$start = new DateTime('2026-01-01');
$end = $start->modify('+1 month'); // $start also modified!
✓ Fixed
// DateTimeImmutable — immutable, testable, timezone-aware:
$expiry = (new DateTimeImmutable())->modify('+30 days')->format('Y-m-d');
$xmas   = new DateTimeImmutable('2026-12-25', new DateTimeZone('UTC'));

$birth = new DateTimeImmutable($user->birthdate);
$age   = (new DateTimeImmutable())->diff($birth)->y;

// Immutable — original unchanged:
$start = new DateTimeImmutable('2026-01-01');
$end   = $start->modify('+1 month'); // $start unchanged

Added 16 Mar 2026
Edited 22 Mar 2026
Views 46
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 2 pings T 0 pings F 3 pings S 3 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 1 ping M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 2 pings M 1 ping T 0 pings W
No pings yet today
SEMrush 1
Scrapy 8 Amazonbot 7 Perplexity 5 Google 5 Ahrefs 4 Unknown AI 3 Majestic 2 ChatGPT 2 Claude 1 Meta AI 1 PetalBot 1 SEMrush 1
crawler 36 crawler_json 3 pre-tracking 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
Replace date() and mktime() with DateTimeImmutable — date() uses the server timezone silently; DateTimeImmutable forces you to be explicit about timezone from construction
📦 Applies To
PHP 5.0+ web cli
🔗 Prerequisites
🔍 Detection Hints
date() mktime() strtotime() without explicit timezone; mixing timestamps and formatted strings; date_create() instead of DateTimeImmutable
Auto-detectable: ✓ Yes phpstan rector php-cs-fixer
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: Line Tests: Update


✓ schema.org compliant