-
Notifications
You must be signed in to change notification settings - Fork 11.6k
Description
Laravel Version
12.*
PHP Version
8.4.*
Database Driver & Version
No response
Description
date_format:Y-m-d H:i:s fails for datetimes that fall into DST transitions when the app timezone (or date_default_timezone_set) is set to a DST-observing zone (e.g. Europe/Amsterdam, Europe/London, Europe/Athens).
During DST start, certain local times are non-existent (e.g. in Amsterdam on 2025-03-30, 02:00:00 → 02:59:59 does not exist). The validator appears to parse and normalize the input using the current timezone, so DateTime::createFromFormat('!Y-m-d H:i:s', '2025-03-30 02:00:00') becomes 2025-03-30 03:00:00 (normalized), which then fails the strict equality check in the validation rule—even though the input string matches the declared format exactly.
In short: DST normalization changes the parsed time and the rule reports the format as invalid.
Steps To Reproduce
1- Set the PHP default timezone to a DST zone (Amsterdam shown here).
2- Validate a string that matches Y-m-d H:i:s and falls in the DST “gap”.
<?php
use Illuminate\Support\Facades\Validator;
date_default_timezone_set('Europe/Amsterdam');
$payload = ['ts' => '2025-03-30 02:00:00']; // Local time that doesn't exist due to DST shift (+1h)
$rules = ['ts' => 'date_format:Y-m-d H:i:s'];
$validator = Validator::make($payload, $rules);
var_dump($validator->passes()); // false
var_dump($validator->errors()->all());
// ["The ts does not match the format Y-m-d H:i:s."]
Script to find which date will fail:
<?php
date_default_timezone_set('Europe/Amsterdam');
$year = 2025;
for ($month = 1; $month <= 12; $month++) {
$daysInMonth = match ($month) {
1, 3, 5, 7, 8, 10, 12 => 31,
4, 6, 9, 11 => 30,
2 => 28,
default => throw new Exception("Invalid month: $month"),
};
for ($day = 1; $day <= $daysInMonth; $day++) {
for ($hour = 0; $hour < 24; $hour++) {
$date = sprintf("$year-%02d-%02d %02d:00:00", $month, $day, $hour);
$dateFormated = DateTime::createFromFormat('!Y-m-d H:i:s', $date)->format('Y-m-d H:i:s');
if ($dateFormated !== $date) {
echo "Date that will thrown exception: $dateFormated !== $date\n";
}
}
}
}
Additional Context
Timezones which breaks is when it has a summer time and it's +x