Signature
date_create(string $datetime = "now", ?DateTimeZone $timezone = null): DateTime|falsePurpose
date_create() turns a date and time string into a mutable DateTime object. It is the procedural form of new DateTime(...). The key difference is how it reports bad input: the constructor throws an exception, while date_create() quietly returns false. That makes it convenient when you want to test a string with a simple if and skip try/catch.
Signature
Parameters and defaults
$datetimeis a string that PHP's date parser understands. The default is"now", so callingdate_create()with no arguments gives you the current moment. Absolute values such as2024-03-15 14:30:00and relative phrases such as+1 monthornext mondayare both accepted, and they can be combined in one string.$timezoneis an optionalDateTimeZoneobject, defaulting tonull. When it isnull, PHP uses the default timezone, which you can set withdate_default_timezone_set(). The argument is not applied when the string already carries its own zone information, such as an offset like+02:00, a zone abbreviation, or an@Unix timestamp.
The manual refers to the constructor of DateTimeImmutable for the full list of accepted string formats, since the parsing rules are shared.
Return value and failure
On success you get a new DateTime instance. On failure, such as a string the parser cannot understand, you get false. No exception is thrown and no object is created, so any method call on the result without a check would cause an error. Always compare against false before using the value, unless the input is a literal you control.
Example 1: parsing a fixed string
The default timezone is set explicitly, so the output does not depend on the server configuration.
date_default_timezone_set('UTC');
$date = date_create('2024-03-15 14:30:00');
echo $date->format('Y-m-d H:i:s T'), "\n";2024-03-15 14:30:00 UTC
Example 2: supplying a timezone
The same wall-clock text means a different instant depending on the zone. Here the string is read as New York local time, which is daylight saving time in July.
date_default_timezone_set('UTC');
$zone = new DateTimeZone('America/New_York');
$date = date_create('2024-07-04 09:00:00', $zone);
echo json_encode([
'local' => $date->format('Y-m-d H:i:s T P'),
'timestamp' => $date->getTimestamp(),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"local":"2024-07-04 09:00:00 EDT -04:00","timestamp":1720098000}
Example 3: relative text and invalid input
A valid string can contain a relative part, and an invalid one produces false.
date_default_timezone_set('UTC');
$valid = date_create('2024-01-31 +1 month');
$invalid = date_create('not a real date');
echo json_encode([
'overflow' => $valid->format('Y-m-d'),
'invalid' => $invalid,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"overflow":"2024-03-02","invalid":false}
Notice that January 31 plus one month does not land on the end of February. PHP adds one to the month number, gets February 31, and rolls the surplus days into March.
Edge cases
- Overflowing days are not errors. A string such as
2024-02-30is parsed successfully and becomes March 1 in a leap year. If you need strict calendar validation, check the components withcheckdate()or usedate_parse()and examine its warnings. - Embedded zones win. If the string says
2024-03-15 10:00:00 +02:00, the$timezoneargument does not change the result. - Timestamps. A string like
@1720098000is read as a Unix timestamp and the resulting object uses the UTC offset+00:00, regardless of the default zone. - "now" is not deterministic. Calling the function without arguments depends on the clock, so avoid it in tests that need stable output.
- Mutability. The returned
DateTimechanges in place when you call methods such asmodify()orsetDate(). Two variables holding the same object see the same change.
Common mistakes
- Not checking for
false. Writingdate_create($input)->format(...)on user input fails when the string is invalid. Store the result, test it with=== false, then use it. - Relying on the default timezone by accident. Without an explicit zone, the same code can behave differently between environments. Set the zone or pass a
DateTimeZone. - Expecting strict validation. The parser is forgiving, so a successful return does not prove the input was a real calendar date in the form you wanted. For a fixed input format,
date_create_from_format()is a better fit. - Passing a string as the timezone. The second parameter must be a
DateTimeZoneobject ornull, not a name like'UTC'. - Mutating a shared object. When you need to derive several dates from one base, clone the object or use an immutable variant.
Related functions
date_create_immutable()returns aDateTimeImmutable, so later changes produce new objects.date_create_from_format()parses a string using an explicit format.DateTime::__construct()is the object-oriented equivalent that throws on failure.date_default_timezone_set()controls the fallback zone.date_parse()andcheckdate()help with diagnosing and validating input.
Recap
date_create() builds a DateTime from a string and an optional DateTimeZone, and returns false instead of throwing when parsing fails. Set your timezone deliberately, remember that an embedded zone overrides the argument, expect forgiving day rollover, and check for false before calling any method on the result.
Tested examples
date_default_timezone_set('UTC');
$date = date_create('2024-03-15 14:30:00');
echo $date->format('Y-m-d H:i:s T'), "\n";2024-03-15 14:30:00 UTC
date_default_timezone_set('UTC');
$zone = new DateTimeZone('America/New_York');
$date = date_create('2024-07-04 09:00:00', $zone);
echo json_encode([
'local' => $date->format('Y-m-d H:i:s T P'),
'timestamp' => $date->getTimestamp(),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"local":"2024-07-04 09:00:00 EDT -04:00","timestamp":1720098000}
date_default_timezone_set('UTC');
$valid = date_create('2024-01-31 +1 month');
$invalid = date_create('not a real date');
echo json_encode([
'overflow' => $valid->format('Y-m-d'),
'invalid' => $invalid,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"overflow":"2024-03-02","invalid":false}