Any PHP application has to deal at some point with date and time and there are so many ways to get it wrong in PHP that I thought I would give some tips on how to properly handle them in modern PHP. My post will assume that you are using the currently stable release of PHP, which is at the time of writing PHP 5.6. That being said I’ll indicate for each advice the minimum PHP version required to start using it.
Configuring your PHP environment
You should always make sure you control your application timezone settings. To do so, since PHP 5.1, you can use the date_default_timezone_set function. Of note, since PHP5.3, if you do not properly set the timezone of your application an E_WARNING
alert will be throw.
Of course, you can always at any given time retrieve your current setting with the date_default_timezone_get function.
<?php
//ideally in your application bootstrap before anything else
date_default_timezone_set('Africa/Kinshasa');
echo date_default_timezone_get(); //displays 'Africa/Kinshasa'
If there’s one thing to take away from this post is that not knowing or incorrectly setting your environment will always result on unexpected bugs no matter what you do.
NB: This is a good time to also check that your back-end (database, filesystem, …) is also correctly set to further avoid bugs when saving/retrieving data from it
PHP Internal solutions
Prior to PHP 5.2, the language dealt with date and time using at least 4 functions.
Since then, PHP has mature and offers a complete set of classes to properly deal with date and time. Once you’ll start using them you will never want to use the older mechanism again. Here’s the complete list of classes and the PHP version they were introduced in:
- DateTimeZone since PHP 5.2
- DateTime since PHP 5.2
- DateTimeImmutable since PHP 5.5
- DateInterval since PHP 5.3
- DatePeriod since PHP 5.3
With these 5 classes anything can be done around dates, time and time ranges. Since this post is about tips, you should refer to the PHP Documentation website to understand how they work.
To be fair, you will mostly work with the DateTime
class. But knowing how and when to use the other classes is as fundamental as you will most likely need them at some point in your development. You should keep in mind the following tips:
- There is no
__toString
method attached to any of these classes. - For modifying methods
DateTime
uses a fluent interface since PHP 5.3. - When creating a new
DateTime
object if noDateTimeZone
is specified, the object will fallback to the timezone specified bydate_default_timezone_set
.
<?php
date_default_timezone_set('Africa/Douala');
$dt1 = new DateTime('2014-10-12 14:23:13');
$dt2 = new DateTime('2014-10-12 14:23:13', new DateTimeZone('Africa/Nairobi'));
echo $dt1->format(DateTime::W3C), PHP_EOL; //2014-10-12T14:23:13+01:00
echo $dt2->format(DateTime::W3C), PHP_EOL; //2014-10-12T14:23:13+03:00
- You can compare two
DateTime
objects directly using standard comparison.
<?php
$dt1 = new DateTime('-1 HOUR');
$dt2 = new DateTime('+3 DAYS');
if ($dt1 > $dt2) {
echo 'dt1 is greater than dt2', PHP_EOL;
} elseif ($dt1 < $dt2) {
echo 'dt1 is less than dt2', PHP_EOL;
} else {
echo 'dt1 equals dt2', PHP_EOL;
}
- The difference between two
DateTime
objects is expressed as aDateInterval
object.
<?php
date_default_timezone_set('Africa/Douala');
$dt1 = new DateTime('-1 HOUR');
$dt2 = new DateTime('NOW', new DateTimeZone('Africa/Nairobi'));
$diff = $dt1->diff($dt2); //$diff is a DateInterval object
echo $diff->h; //display '1'
Since PHP 5.5 DateTime
and DateTimeImmutable
implements the same DateTimeInterface
interface and exposed the same methods. You can compare, and expressed the difference between objects of both class like previously shown.
The main difference between both classes is that DateTimeImmutable
is a immutable value object. This means that for all modifying methods a DateTimeImmutable
object always returns a new modified copy of itself while a DateTime
object modifies itself.
<?php
$dt = new DateTime();
$dtim = new DateTimeImmutable();
$dtim == $dt; //returns true
$dt->add(new DateInterval('PT1H')) //adding a 1 hour interval
->sub(new DateInterval('P3D')); //removing an interval of 3 days
$newDtim = $dtim->add(new DateInterval('PT1H'))
->sub(new DateInterval('P3D'));
$newDtim == $dt; //returns true
$dtim == $dt; //returns false because $dt has changed NOT $dtim
For time ranges you can use the DatePeriod
class. It generates DateTime
objects contained within a specific time range at a given interval.
- When creating a
DatePeriod
with an end datetime, the latter is excluded from the generated time range.
<?php
$end = new DateTime('+4 DAYS');
$period = new DatePeriod(
new DateTime('TODAY'),
new DateInterval('P1D'),
$end
);
$res = iterator_to_array($period, false);
echo count($res); //returns 5;
array_pop($res) != $end; // returns true;
- Alternatively, you can create a
DatePeriod
class using recurrences not occurences to indicate the number ofDateTime
objects to be generated.
<?php
$period = new DatePeriod(
new DateTime(),
new DateInterval('P1D'),
3 //recurrences
);
echo count(iterator_to_array($period, false)); //return 4;
Open source solutions
I have to admit, sometimes, working with the above classes can be tricky. This is where the PHP Open Source Community comes handy. So instead of trying to reinvent the wheels here’s two classes to help you with date and time in PHP.
Carbon
Carbon from @NesbittBrian supercharges the DateTime
object with many useful methods and/or properties. The class requires PHP 5.3
This class extends PHP internal DateTime
class. Which means that anywhere the DateTime
object is required you can safely substitute it with a Carbon
instance and gain many useful getter and setter methods to truly ease DateTime
usage.
For example, Carbon
implements the __toString
method and provide a simple mean to access each part of your DateTime
object with intuitive getters properties. More information can be found on the github homepage.
Period
Period, is a package that I’ve created and maintained as a php league package. The package contains the Period
class which deals with time range. The class requires PHP 5.3
This class handles time range in a uniform and predicable way. Just like Carbon
the class comes with many useful named constructors and can be used with Carbon
objects. The class compares and modifies time range easily by being an immutable value object just like the DateTimeImmutable
object.
Of course, as both classes are open sourced on Github, Carbon and Period are easily available using composer and you are welcome to contribute to their respective code source to improve them.
Conclusion
Dealing with date/time in PHP has evolved a great deal since PHP5 has been around and it has never been much easier. So when adding date and time capabilities in your next project, remember to use the correct class and/or to look into the open source community effort to further improve your code.
Hi!
In the paragraph related to your Period library you said it requires PHP 5.3. But http://period.thephpleague.com/installation/ says it requires PHP 5.5.
I understand your concern but that’s because version number and PHP requirements have since been upgraded. Version 2.0 did require PHP 5.3 but as of now the latest stable version version 2.5.1 requires PHP 5.4. Since PHP 5.3 is EOL and PHP 5.4 will be EOL in September a new version 3.0 is schedule to be release later this year and will require PHP 5.5.9. The simplest way to follow/meet the requirements its to use composer to install the package. Composer will select and install the best version according to your PHP environment.