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.

DurationDateInterval parameter
1 secondPT1S
10 secondsPT10S
1 minutePT1M, PT60S
10 minutesPT10M, PT600S
1 hourPT1H, PT60M, PT3600S
1 dayP1D, PT24H
1 weekP7D
1 monthP1M
18 monthsP18M
1 yearP1Y, P365D
10 yearsP10Y, 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 great thing about this format is that you can combine years, months, days and time together.

DurationDateInterval parameter
1 day and 1 hourP1DT1H
1 year and 1 dayP1Y1D
1 year, 1 day, 1 hour and 1 minuteP1Y1DT1H1M

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:

Formats available for the dates (years, months and days)

ConstantResult with locale "en"
IntlDateFormatter::SHORT2/1/23
IntlDateFormatter::MEDIUMFeb 1, 2023
IntlDateFormatter::LONGFebruary 1, 2023
IntlDateFormatter::FULLWednesday, February 1, 2023
IntlDateFormatter::TRADITIONALWednesday, February 1, 2023
IntlDateFormatter::GREGORIANFebruary 1, 2023
IntlDateFormatter::NONE20230201

Formats available for the time (hours and minutes)

ConstantResult with locale "en"
IntlDateFormatter::SHORT12:00 AM
IntlDateFormatter::MEDIUM12:00:00 AM
IntlDateFormatter::LONG12:00:00 AM GMT
IntlDateFormatter::FULL12:00:00 AM GMT
IntlDateFormatter::TRADITIONAL12:00:00 AM GMT
IntlDateFormatter::GREGORIAN12: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