Signature
date_parse_from_format(string $format, string $datetime): arrayPurpose
date_parse_from_format() reads a date/time string according to a format you supply and returns a detailed array describing what it found. It does not build a DateTime object and it does not throw an exception for malformed input. Instead it reports problems inside the returned array. That makes it useful for validating user input, producing precise diagnostics, or checking which parts of a string were actually provided.
Signature
Parameters
$format: the pattern that describes the layout of the string. The same format characters are used as inDateTimeImmutable::createFromFormat(), for exampleYfor a four-digit year,mornfor the month,dorjfor the day,H/Gfor the hour,ifor minutes,sfor seconds andPfor a UTC offset such as+01:00.$datetime: the string to parse. Neither parameter has a default value; both are required.
Return value and failure cases
The function always returns an array. The main keys are year, month, day, hour, minute, second and fraction, plus warning_count, warnings, error_count, errors and is_localtime.
When the string contains timezone information, is_localtime is true and zone_type tells you the kind: 1 for a UTC offset (adds zone and is_dst), 2 for an abbreviation (adds tz_abbr and is_dst), and 3 for a timezone identifier (adds tz_abbr and tz_id). Since PHP 7.2.0, zone is expressed in seconds, so an offset of +01:00 gives 3600.
The warnings and errors arrays are keyed by the position in the string where the problem occurred, and the value describes it. The manual warns that these arrays can hold fewer entries than warning_count or error_count when several problems occur at the same position, so trust the counts.
The only exception is a ValueError, thrown when $datetime contains NUL bytes. Ordinary bad input never throws.
Example 1: parsing a complete timestamp
When the string matches the format, every part is returned as an integer and the error count is zero.
$p = date_parse_from_format('Y-m-d H:i:s', '2024-03-15 14:30:45');
echo json_encode([
'year' => $p['year'],
'month' => $p['month'],
'day' => $p['day'],
'hour' => $p['hour'],
'minute' => $p['minute'],
'second' => $p['second'],
'errors' => $p['error_count'],
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"year":2024,"month":3,"day":15,"hour":14,"minute":30,"second":45,"errors":0}
Example 2: fields that were not in the format
A part that the format never mentions is not guessed or defaulted to the current time. It comes back as false. This is how you can tell a date-only string from a midnight timestamp.
$p = date_parse_from_format('Y-m-d', '2024-03-15');
echo json_encode([
'year' => $p['year'],
'month' => $p['month'],
'day' => $p['day'],
'hour' => $p['hour'],
'minute' => $p['minute'],
'second' => $p['second'],
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"year":2024,"month":3,"day":15,"hour":false,"minute":false,"second":false}
Example 3: warnings versus errors
A string can match the format and still describe a date that does not exist. 2024-02-31 has a month and day in the right shape, so the parts are returned unchanged, but a warning is recorded. A string that does not match the format at all produces errors.
$feb = date_parse_from_format('Y-m-d', '2024-02-31');
$bad = date_parse_from_format('Y-m-d', 'abc');
echo json_encode([
'month' => $feb['month'],
'day' => $feb['day'],
'warnings' => $feb['warning_count'],
'errors' => $feb['error_count'],
'message' => array_values($feb['warnings'])[0],
'bad_has_errors' => $bad['error_count'] > 0,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"month":2,"day":31,"warnings":1,"errors":0,"message":"The parsed date was invalid","bad_has_errors":true}
Edge cases
- Rolled-over dates are not applied. The function reports
dayas31for February; onlycreateFromFormat()or similar object creation would roll it into March. - A time with an hour that conflicts with its meridian marker (for example
22:30 pmwithG:i a) produces a warning that the parsed time was invalid. - Parsing stops being meaningful after an error, so do not rely on later fields when
error_countis above zero. - Fractions, offsets and timezone names only appear when the format has characters that read them.
Common mistakes
- Checking only the parts. The returned numbers can look fine even when the date is invalid. Always inspect
warning_countanderror_count. - Treating
falseas zero. Unset fields arefalse. A loose comparison such as$p['hour'] == 0is true forfalse, hiding the difference. Use===. - Assuming exceptions. Wrapping the call in
try/catchwill not catch format mismatches. Only NUL bytes in the input raise aValueError. - Mixing formats.
dexpects two digits andjaccepts one or two. Using the wrong one is a frequent source of errors. - Counting array entries.
count($p['errors'])may be smaller thanerror_count; use the count key.
Related functions
DateTimeImmutable::createFromFormat(): builds an object using the same format rules.checkdate(): validates a Gregorian month, day and year combination.date_parse(): parses free-form date strings rather than an exact format.
Recap
date_parse_from_format() gives you a diagnostic breakdown of a date string against an exact format. Read the integer parts, remember that missing parts are false, and treat non-zero warning_count or error_count as the real validity signal.
Tested examples
$p = date_parse_from_format('Y-m-d H:i:s', '2024-03-15 14:30:45');
echo json_encode([
'year' => $p['year'],
'month' => $p['month'],
'day' => $p['day'],
'hour' => $p['hour'],
'minute' => $p['minute'],
'second' => $p['second'],
'errors' => $p['error_count'],
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"year":2024,"month":3,"day":15,"hour":14,"minute":30,"second":45,"errors":0}
$p = date_parse_from_format('Y-m-d', '2024-03-15');
echo json_encode([
'year' => $p['year'],
'month' => $p['month'],
'day' => $p['day'],
'hour' => $p['hour'],
'minute' => $p['minute'],
'second' => $p['second'],
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"year":2024,"month":3,"day":15,"hour":false,"minute":false,"second":false}
$feb = date_parse_from_format('Y-m-d', '2024-02-31');
$bad = date_parse_from_format('Y-m-d', 'abc');
echo json_encode([
'month' => $feb['month'],
'day' => $feb['day'],
'warnings' => $feb['warning_count'],
'errors' => $feb['error_count'],
'message' => array_values($feb['warnings'])[0],
'bad_has_errors' => $bad['error_count'] > 0,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"month":2,"day":31,"warnings":1,"errors":0,"message":"The parsed date was invalid","bad_has_errors":true}