PHP DateTime: The Definitive Guide
Mastering DateTime in PHP with practical examples

How to initialize a new DateTime object
Initializing DateTime without any parameter
DateTime objects can be initialized without any parameter in the constructor.
$dateTime = new DateTime();
The date and time that will be stored in the DateTime object represent the exact moment when the object is initialized.
This is the equivalent of initializing your object with "now" as the first parameter in the constructor.
$dateTime = new DateTime('now');
Initializing DateTime with a string
There is a variety of string formats you can use to create new DateTime objects. The full list of formats is available here.
Initializing DateTime with a DateTimeZone object
DateTime object can take a second parameter in the constructor which is the DateTimeZone object. If you do not set a DateTimeZone object in the constructor of new DateTime objects, the DateTime objects will inherit the timezone set in the server's php.ini file on the date.timezone
field.
What this means is that if date.timezone
is set with the value "America/Los_Angeles" in the php.ini file, new DateTime objects will store the current date and time in Los Angeles if no DateTimeZone is set in the DateTime's constructor.
A DateTimeZone object is initialized like this:
$dateTimeZone = new DateTimeZone('America/New_York');
Then you create a localized DateTime object by inserting the DateTimeZone as the second parameter in the constructor.
$dateTimeZone = new DateTimeZone('America/New_York');
$dateTime = new DateTime('now', $dateTimeZone);
The one-liner version is:
$dateTime = new DateTime('now', new DateTimeZone('America/New_York'));
Take a look at the PHP documentation to get the list of the supported timezones
DateTime and DateTimeZone
Update the time zone
The time zone of any DateTime object can be changed using the setTimeZone
method which requires a DateTimeZone object as parameter.
$dateTime = new DateTime('2023-01-01 00:00:00', new DateTimeZone('Europe/Paris'));
// Change the time zone
$dateTime->setTimezone(new DateTimeZone('America/New_York'));
echo $dateTime->format('Y-m-d H:i:s');
// Output: 2022-12-31 18:00:00
In the example above, we have initialized a new DateTime object with the first day of 2023 in Paris, France. After changing the time to New York city, the date and time stored in the object changed and reflect there is a six hours time difference between the two cities.
Find the time zone
Whether you are not sure of what time zone is stored or you want to manipulate the time zone set in a DateTime object, you can use the getTimeZone
method to return the time zone as a DateTimeZoneObject
$dateTime = new DateTime('2023-01-01 00:00:00');
echo $dateTime->getTimezone()->getName();
// Output: the name of the time zone
About the importance of DateTimeZone
When you create a DateTime object without specifying a timezone, the object will inherit the timezone set in the php.ini file with the date.timezone
field.
If the server where new DateTime()
objects are created is located in Paris/Europe, the objects will store what date and time it is in Paris/Europe. That will be an issue if your project must reflect what time it is, let say in New York.
Let's be crystal clear on this: "2022-12-31 06:00:00 PM" in New York is the exact same moment as "2023-01-01 00:00:00 AM" in Paris but the litteral representation is not the same.
Therefore, you should not let your DateTime objects depends on the timezone already set for you in the server's php.ini configuration.
The best practice is to instantiate your DateTime objects with a DateTimeZone objects so that you always know what is the region of the date and time is stored.
You should always wonder what is the timezone set in your DateTime objects. That's what pro developers do.
How to use DateTime with timestamps
A timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
Timestamps are returned when using PHP functions such as mktime()
, time()
or strtotime()
. They may also be found when in database records or in results returned by an API.
Initializing DateTime with a timestamp
DateTime objects based on timestamps must be initialized with the value of the timestamp prefixed with the character "@".
Examples
$dateTime = new DateTime('@1672531200');
echo $dateTime->format('Y-m-d H:i:s');
// Output: 2023-01-01 00:00:00
$dateTime = new DateTime('@0');
echo $dateTime->format('Y-m-d H:i:s');
// Output: 1970-01-01 00:00:00
Also, remember that the time zone parameter of a new DateTime object will always be ignored when using a timestamp as first parameter. It means the date and time represented by the timestamp will not be automatically converted to the time zone you set in the constructor.
$dateTime = new DateTime('@1672531200', new DateTimeZone('America/New_York');
echo $dateTime->getTimeZone()->getName();
// Output: +00:00 which is equivalent to UTC
You will need to use the setTimeZone
method to update the time zone set in the DateTime object.
What about negative timestamps?
It is possible to create DateTime objects with negative timestamps. If such a use case happens, you will need to prefix the timestamp with "@-".
By using negative timestamps, you go backward starting from January 1, 1970 (midnight UTC/GMT).
// Substract 60 seconds from Unix time
$dateTime = new DateTime('@-60');
echo $dateTime->format('Y-m-d H:i:s');
// Output: 1969-12-31 23:59:00
Get the timestamp of DateTime object
Once you have initialized a new DateTime object, you may need to retrieve the timestamp from this object in order to store the data in your database for example.
You get the timestamp of any DateTime object by using the getTimestamp()
method, which takes a timestamp as parameter.
$dateTime = new DateTime('2023-01-01 00:00:00');
echo $dateTime->getTimestamp();
// Output: 1672531200
Change the timestamp of a DateTime object
You can change the timestamp of any DateTime object by using the setTimestamp()
method.
// Initialize DateTime with the current date and time
$dateTime = new DateTime();
echo $dateTime->setTimestamp(1672531200);
echo $dateTime->format('Y-m-d H:i:s');
// Output: 2023-01-01 00:00:00
Modify DateTime using DateInterval
When you need to add or substract a certain amount of time to a DateTime object, the OOP solution is to initialize a new DateInterval object.
The DateInterval only takes one argument, which is the duration you want to add or substract to your DateTime object.
The duration you must have a specific format depending on whether you are adding seconds, minutes, hours, days, weeks or years to the DateTime object.
Duration | DateInterval parameter |
---|---|
1 second | PT1S |
10 seconds | PT10S |
1 minute | PT1M, PT60S |
10 minutes | PT10M, PT600S |
1 hour | PT1H, PT60M, PT3600S |
1 day | P1D, PT24H |
1 week | P7D |
1 month | P1M |
18 months | P18M |
1 year | P1Y, P365D |
10 years | P10Y, P3650D |
You will notice here that sometimes the interval is prefixed with "P" and sometimes it is prefixed with "PT".
Here is how the format works:
- The interval always starts with "P"
- "P" is followed by years, months and days
- "T" is followed by hours, minutes and seconds
- When there are years, months or days only: the interval is prefixed with "P"
- When there are hours, minutes or seconds only: the interval is prefixed with "PT"
The great thing about this format is that you can combine years, months, days and time together.
Duration | DateInterval parameter |
---|---|
1 day and 1 hour | P1DT1H |
1 year and 1 day | P1Y1D |
1 year, 1 day, 1 hour and 1 minute | P1Y1DT1H1M |
The unit types must be entered from the largest scale unit to the smallest scale unit. It means years must be inserted before months, months must be inserted before days, days must be inserted before minutes, etc.
For example, when handling "one month and five days", "P1M5D" is valid interval format but "P5D1M" is not.
Use DateInterval object as much as you can when your DateTime objects require to be modified. Date intervals are based on the ISO 8601 duration standard whereas the modify() method is specific to PHP.
Once you understand understood how DateInterval works, adding or substracting a duration to a DateTime object is pretty straightforward.
Add duration to DateTime with DateInterval object
$datetime = new DateTime('2037-01-01');
// Add 20 days
$datetime->add(new DateInterval('P20D'));
echo $datetime->format('Y-m-d H:i:s');
// Output: "2037-01-21 00:00:00"
Substract duration to DateTime with DateInterval object
$datetime = new DateTime('2037-01-21');
// Substract 20 days
$datetime->sub(new DateInterval('P20D'));
echo $datetime->format('Y-m-d H:i:s');
// Output: "2037-01-01 00:00:00"
Translate DateTime with IntlDateFormatter
The best practice to translate dates and times stored in DateTime object is to use the IntlDateFormatter class because IntlDateFormatter can arrange DateTime objects with pretty much any format you would need in your project.
You translate DateTime objects by calling the formatObject()
method from an IntlDateFormatter instance.
The formatObject()
method requires four parameters:
- The DateTime object you want to format
- The date format
- The time format
- The locale of the format, which is the language in which you want the date and time translated
Formats available for the dates (years, months and days)
Constant | Result with locale "en" |
---|---|
IntlDateFormatter::SHORT | 2/1/23 |
IntlDateFormatter::MEDIUM | Feb 1, 2023 |
IntlDateFormatter::LONG | February 1, 2023 |
IntlDateFormatter::FULL | Wednesday, February 1, 2023 |
IntlDateFormatter::TRADITIONAL | Wednesday, February 1, 2023 |
IntlDateFormatter::GREGORIAN | February 1, 2023 |
IntlDateFormatter::NONE | 20230201 |
Formats available for the time (hours and minutes)
Constant | Result with locale "en" |
---|---|
IntlDateFormatter::SHORT | 12:00 AM |
IntlDateFormatter::MEDIUM | 12:00:00 AM |
IntlDateFormatter::LONG | 12:00:00 AM GMT |
IntlDateFormatter::FULL | 12:00:00 AM GMT |
IntlDateFormatter::TRADITIONAL | 12:00:00 AM GMT |
IntlDateFormatter::GREGORIAN | 12:00:00 AM GMT |
Which locale should you choose?
A locale can either be a language code ("de", "en", "fr", etc.) or a combination of a language code with a country code ("en_US", "de_DE", etc.).
If you use a language code only, such as "en", the date will be translated in plain english
If you use a language code and a country code, such as "en_DE", the date will be translated in plain english and formatted as it came from a german calendar.
Examples
Once you have identified the date and time formats you need along with the language code, you can start using IntlDateFormatter.
IntlDateFormatter with english locale
$dateTime = new DateTime('2023-02-03 13:37:00');
$dateFormat = IntlDateFormatter::LONG;
$timeFormat = IntlDateFormatter::SHORT;
$locale = 'en';
echo IntlDateFormatter::formatObject($dateTime, [$dateFormat, $timeFormat], $locale);
// Output: February 3, 2023 at 1:37 PM
IntlDateFormatter with french locale
$dateTime = new DateTime('2023-02-03 13:37:00');
$dateFormat = IntlDateFormatter::LONG;
$timeFormat = IntlDateFormatter::SHORT;
$locale = 'fr';
echo IntlDateFormatter::formatObject($dateTime, [$dateFormat, $timeFormat], $locale);
// Output: 3 février 2023 13:37
You can see the importance of choosing the locale carefully. The date and time rendering will always be based on the locale you insert as a parameter in format formatObjet().
Translating part of a date with IntlDateFormatter
You may be interested in translating the month only from a date. To do so you will to use the setPattern()
method on the formatter.
$dateTime = new DateTime('2023-02-03 13:37:00');
$formatter = new IntlDateFormatter('en_US', IntlDateFormatter::NONE, IntlDateFormatter::NONE);
$formatter->setPattern('MMMM yyyy');
echo $formatter->format($dateTime);
// Output: February 2023
Technical requirements for IntlDateFormatter
IntlDateFormatter requires the intl extension to be installed and enabled in PHP.
In the php.ini file change ;extension=php_intl.dll
to extension=php_intl.dll