PHP Date/Timezone Pitfalls
Also Known As
PHP timezone
DateTime timezone
Carbon
date_default_timezone_set
TL;DR
Common PHP date and timezone bugs — relying on date_default_timezone_set(), comparing DateTime objects across timezones, and strtotime() ambiguity.
Explanation
PHP date pitfalls: date_default_timezone_set() is process-wide — changing it affects all date operations globally. DateTime is mutable (use DateTimeImmutable). strtotime() is locale-dependent and silently returns false for invalid strings. Comparing DateTime across timezones: two DateTime objects representing the same instant but different timezones compare as unequal by value. Carbon wraps DateTimeImmutable with testing support (Carbon::setTestNow()). Always: store UTC, display in user's timezone, use DateTimeImmutable, validate date strings explicitly.
Common Misconception
✗ date_default_timezone_set() is safe to call in library code — calling it in a library changes the timezone for the entire application, breaking any code that relies on the previous timezone setting.
Why It Matters
A PHP application without explicit timezone handling shows different times to users in different regions, stores ambiguous timestamps that cannot be reliably converted, and breaks during DST transitions.
Common Mistakes
- Calling date_default_timezone_set() in library code — it is a global setting; libraries must never change it.
- DateTime instead of DateTimeImmutable — mutation surprises when DateTime is passed to functions.
- Comparing DateTime objects with == — compares string representation not the same instant.
- strtotime() without checking for false — invalid strings return false which converts to timestamp 0 (1970).
Code Examples
✗ Vulnerable
// Mutable DateTime — surprise mutation:
$start = new DateTime('2026-01-01');
$end = $start->modify('+1 month'); // $start is also modified!
echo $start->format('Y-m-d'); // 2026-02-01 — not 2026-01-01!
// Timezone comparison bug:
$utc = new DateTime('12:00', new DateTimeZone('UTC'));
$bst = new DateTime('13:00', new DateTimeZone('Europe/London')); // Same instant
var_dump($utc == $bst); // false — same instant, different representation
✓ Fixed
// DateTimeImmutable — safe:
$start = new DateTimeImmutable('2026-01-01');
$end = $start->modify('+1 month'); // $start unchanged
echo $start->format('Y-m-d'); // 2026-01-01 — correct
// Correct comparison — convert to same timezone or compare timestamps:
$utc = new DateTimeImmutable('12:00', new DateTimeZone('UTC'));
$bst = new DateTimeImmutable('13:00', new DateTimeZone('Europe/London'));
var_dump($utc->getTimestamp() === $bst->getTimestamp()); // true
// Validate before using strtotime:
$ts = strtotime($userInput);
if ($ts === false) throw new InvalidArgumentException('Invalid date');
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
16 Mar 2026
Edited
22 Mar 2026
Views
25
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Perplexity 7
Amazonbot 6
Google 3
ChatGPT 2
Ahrefs 1
Also referenced
How they use it
crawler 16
crawler_json 3
⚡
DEV INTEL
Tools & Severity
🟠 High
⚙ Fix effort: Low
⚡ Quick Fix
Set date.timezone = UTC in php.ini and always pass explicit DateTimeZone objects — relying on the system timezone causes bugs when servers are in different regions
📦 Applies To
PHP 5.1+
web
cli
queue-worker
🔗 Prerequisites
🔍 Detection Hints
date.timezone not set in php.ini; date_default_timezone_set() in application code; DateTimeImmutable without explicit timezone
Auto-detectable:
✓ Yes
phpstan
lynis
phpinfo
⚠ Related Problems
🤖 AI Agent
Confidence: Medium
False Positives: Medium
✗ Manual fix
Fix: Medium
Context: File
Tests: Update