{"id":2313,"date":"2014-11-19T15:16:12","date_gmt":"2014-11-19T13:16:12","guid":{"rendered":"http:\/\/www.nyamsprod.com\/blog\/?p=2313"},"modified":"2015-04-07T15:49:20","modified_gmt":"2015-04-07T13:49:20","slug":"dealing-with-date-and-time-in-modern-php","status":"publish","type":"post","link":"https:\/\/nyamsprod.com\/blog\/dealing-with-date-and-time-in-modern-php\/","title":{"rendered":"Dealing with date and time in modern PHP"},"content":{"rendered":"<div class=\"message warning\">\n<p><strong>Attention:<\/strong> Les informations de ce billet sont susceptibles d'&ecirc;tre obsol&egrave;tes car vieux de plus 2 ans.<\/p>\n<p><strong>Warning: <\/strong> The information you are reading may be obsolete, this post was published more than 2 years ago.<\/p>\n<\/div><p>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 <em>PHP 5.6<\/em>. That being said I&#8217;ll indicate for each advice the minimum PHP version required to start using it.<!--more--><\/p>\n<h2>Configuring your PHP environment<\/h2>\n<p>You should always make sure you control your application timezone settings. To do so, since PHP 5.1, you can use the <a title=\"date_default_timezone_set on php.net\" href=\"http:\/\/php.net\/date_default_timezone_set\">date_default_timezone_set<\/a> function. Of note, since PHP5.3, if you do not properly set the timezone of your application an <code>E_WARNING<\/code> alert will be throw.<\/p>\n<p>Of course, you can always at any given time retrieve your current setting with the <a title=\"date_default_timezone_get on php.net\" href=\"http:\/\/php.net\/date_default_timezone_get\">date_default_timezone_get<\/a> function.<\/p>\n<pre><code class=\"language-php\">&lt;?php\r\n\/\/ideally in your application bootstrap before anything else\r\ndate_default_timezone_set('Africa\/Kinshasa');\r\necho date_default_timezone_get(); \/\/displays 'Africa\/Kinshasa'<\/code><\/pre>\n<p>If there&#8217;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.<\/p>\n<p><strong>NB: This is a good time to also check that your back-end (database, filesystem, &#8230;) is also correctly set to further avoid bugs when saving\/retrieving data from it<\/strong><\/p>\n<h2>PHP Internal solutions<\/h2>\n<p>Prior to PHP 5.2, the language dealt with date and time using at least 4 functions.<\/p>\n<ul>\n<li><a title=\"time on php.net\" href=\"http:\/\/php.net\/time\">time<\/a><\/li>\n<li><a title=\"date on php.net\" href=\"http:\/\/php.net\/date\">date<\/a><\/li>\n<li><a title=\"mktime on php.net\" href=\"http:\/\/php.net\/mktime\">mktime<\/a><\/li>\n<li><a title=\"strtotime on php.net\" href=\"http:\/\/php.net\/strtotime\">strtotime<\/a><\/li>\n<\/ul>\n<p>Since then, PHP has mature and offers <a title=\"Date and Time Book on php.net\" href=\"http:\/\/php.net\/datetime\">a complete set of classes<\/a> to properly deal with date and time. Once you&#8217;ll start using them you will never want to use the <em>older<\/em> mechanism again. Here&#8217;s the complete list of classes and the PHP version they were introduced in:<\/p>\n<ul>\n<li><a title=\"DateTimeZone on php.net\" href=\"http:\/\/php.net\/class.datetimezone\">DateTimeZone<\/a> <em>since PHP 5.2<\/em><\/li>\n<li><a title=\"DateTime on php.net\" href=\"http:\/\/php.net\/class.datetime\">DateTime<\/a> <em>since PHP 5.2<\/em><\/li>\n<li><a title=\"time on php.net\" href=\"http:\/\/php.net\/class.datetimeimmutable\">DateTimeImmutable<\/a> <em>since PHP 5.5<\/em><\/li>\n<li><a title=\"DateTimeInterval on php.net\" href=\"http:\/\/php.net\/class.dateinterval\">DateInterval<\/a> <em>since PHP 5.3<\/em><\/li>\n<li><a title=\"DatePeriod on php.net\" href=\"http:\/\/php.net\/class.dateperiod\">DatePeriod<\/a> <em>since PHP 5.3<\/em><\/li>\n<\/ul>\n<p>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.<\/p>\n<p>To be fair, you will mostly work with the <code>DateTime<\/code> 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:<\/p>\n<ul>\n<li>There is no <code>__toString<\/code> method attached to any of these classes.<\/li>\n<li>For modifying methods <code>DateTime<\/code> uses a fluent interface <strong>since PHP 5.3<\/strong>.<\/li>\n<li>When creating a new <code>DateTime<\/code> object if no <code>DateTimeZone<\/code> is specified, the object will fallback to the timezone specified by <code>date_default_timezone_set<\/code>.<\/li>\n<\/ul>\n<pre><code class=\"language-php\">&lt;?php\r\ndate_default_timezone_set('Africa\/Douala');\r\n$dt1 = new DateTime('2014-10-12 14:23:13');\r\n$dt2 = new DateTime('2014-10-12 14:23:13', new DateTimeZone('Africa\/Nairobi'));\r\necho $dt1-&gt;format(DateTime::W3C), PHP_EOL; \/\/2014-10-12T14:23:13+01:00\r\necho $dt2-&gt;format(DateTime::W3C), PHP_EOL; \/\/2014-10-12T14:23:13+03:00\r\n<\/code><\/pre>\n<ul>\n<li>You can compare two <code>DateTime<\/code> objects directly using standard comparison.<\/li>\n<\/ul>\n<pre><code class=\"language-php\">&lt;?php\r\n$dt1 = new DateTime('-1 HOUR'); \r\n$dt2 = new DateTime('+3 DAYS'); \r\nif ($dt1 &gt; $dt2) {\r\n    echo 'dt1 is greater than dt2', PHP_EOL;\r\n} elseif ($dt1 &lt; $dt2) {\r\n    echo 'dt1 is less than dt2', PHP_EOL;\r\n} else {\r\n    echo 'dt1 equals dt2', PHP_EOL;\r\n}\r\n<\/code><\/pre>\n<ul>\n<li>The difference between two <code>DateTime<\/code> objects is expressed as a <code>DateInterval<\/code> object.<\/li>\n<\/ul>\n<pre><code class=\"language-php\">&lt;?php\r\ndate_default_timezone_set('Africa\/Douala');\r\n$dt1 = new DateTime('-1 HOUR');\r\n$dt2 = new DateTime('NOW', new DateTimeZone('Africa\/Nairobi'));\r\n$diff = $dt1-&gt;diff($dt2); \/\/$diff is a DateInterval object\r\necho $diff-&gt;h; \/\/display '1'\r\n<\/code><\/pre>\n<p><strong>Since PHP 5.5<\/strong> <code>DateTime<\/code> and <code>DateTimeImmutable<\/code> implements the same <code>DateTimeInterface<\/code> interface and exposed the same methods. You can compare, and expressed the difference between objects of both class like previously shown.<\/p>\n<p>The main difference between both classes is that <code>DateTimeImmutable<\/code> is a immutable value object. This means that for all modifying methods a <code>DateTimeImmutable<\/code> object always returns a new modified copy of itself while a <code>DateTime<\/code> object modifies itself.<\/p>\n<pre><code class=\"language-php\">&lt;?php\r\n$dt = new DateTime();\r\n$dtim = new DateTimeImmutable();\r\n$dtim == $dt; \/\/returns true\r\n$dt-&gt;add(new DateInterval('PT1H')) \/\/adding a 1 hour interval\r\n    -&gt;sub(new DateInterval('P3D')); \/\/removing an interval of 3 days\r\n$newDtim = $dtim-&gt;add(new DateInterval('PT1H'))\r\n            -&gt;sub(new DateInterval('P3D'));\r\n$newDtim == $dt; \/\/returns true\r\n$dtim == $dt; \/\/returns false because $dt has changed NOT $dtim\r\n<\/code><\/pre>\n<p>For time ranges you can use the <code>DatePeriod<\/code> class. It generates <code>DateTime<\/code> objects contained within a specific time range at a given interval.<\/p>\n<ul>\n<li>When creating a <code>DatePeriod<\/code> with an end datetime, the latter is excluded from the generated time range.<\/li>\n<\/ul>\n<pre><code class=\"language-php\">&lt;?php\r\n$end = new DateTime('+4 DAYS');\r\n$period = new DatePeriod(\r\n    new DateTime('TODAY'),\r\n    new DateInterval('P1D'),\r\n    $end\r\n);\r\n$res = iterator_to_array($period, false);\r\necho count($res); \/\/returns 5;\r\narray_pop($res) != $end; \/\/ returns true;\r\n<\/code><\/pre>\n<ul>\n<li>Alternatively, you can create a <code>DatePeriod<\/code> class using <strong>recurrences<\/strong> not <strong>occurences<\/strong> to indicate the number of <code>DateTime<\/code> objects to be generated.<\/li>\n<\/ul>\n<pre><code class=\"language-php\">&lt;?php\r\n$period = new DatePeriod(\r\n    new DateTime(),\r\n    new DateInterval('P1D'),\r\n    3 \/\/recurrences\r\n);\r\n\r\necho count(iterator_to_array($period, false)); \/\/return 4;\r\n<\/code><\/pre>\n<h2>Open source solutions<\/h2>\n<p>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&#8217;s two classes to help you with date and time in PHP.<\/p>\n<h3>Carbon<\/h3>\n<p><a title=\"Carbon Documentation\" href=\"https:\/\/github.com\/briannesbitt\/Carbon\">Carbon<\/a> from <a title=\"@NesbittBrian on twitter\" href=\"http:\/\/twitter.com\/NesbittBrian\">@NesbittBrian<\/a> supercharges the <code>DateTime<\/code> object with many useful methods and\/or properties. The class requires <em>PHP 5.3<\/em><\/p>\n<p>This class extends PHP internal <code>DateTime<\/code> class. Which means that anywhere the <code>DateTime<\/code> object is required you can safely substitute it with a <code>Carbon<\/code> instance and gain many useful getter and setter methods to truly ease <code>DateTime<\/code> usage.<\/p>\n<p>For example, <code>Carbon<\/code> implements the <code>__toString<\/code> method and provide a simple mean to access each part of your <code>DateTime<\/code> object with intuitive getters properties. More information can be found on the <a href=\"https:\/\/github.com\/briannesbitt\/Carbon\">github homepage<\/a>.<\/p>\n<h3>Period<\/h3>\n<p><a title=\"Period Documentation\" href=\"http:\/\/period.thephpleague.com\/\">Period<\/a>, is a package that I&#8217;ve created and maintained as a <a title=\"the php league of extraordinary packages\" href=\"http:\/\/thephpleague.com\">php league<\/a> package. The package contains the <code>Period<\/code> class which deals with time range. The class requires <em>PHP 5.3<\/em><\/p>\n<p>This class handles time range in a uniform and predicable way. Just like <code>Carbon<\/code> the class comes with many useful named constructors and can be used with <code>Carbon<\/code> objects. The class compares and modifies time range easily by being an immutable value object just like the <code>DateTimeImmutable<\/code> object.<\/p>\n<p>Of course, as both classes are open sourced on Github, <a title=\"Carbon on packagist\" href=\"https:\/\/packagist.org\/packages\/nesbot\/carbon\">Carbon<\/a> and <a title=\"Period on Packagist\" href=\"http:\/\/packagist.org\/packages\/league\/period\">Period<\/a> are easily available using <a title=\"Composer website\" href=\"http:\/\/getcomposer.org\">composer<\/a> and you are welcome to contribute to their respective code source to improve them.<\/p>\n<h2>Conclusion<\/h2>\n<p>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.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Tips on how to handle date and time in modern PHP using the Date\/Time classes and Open Source solutions.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[5],"tags":[778,770,780,781,771,779,783,777,412,782],"class_list":["post-2313","post","type-post","status-publish","format-standard","hentry","category-web","tag-carbon","tag-date","tag-dateinterval","tag-dateperiod","tag-datetime","tag-datetimezone","tag-mktime","tag-period","tag-php","tag-strtotime"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/posts\/2313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/comments?post=2313"}],"version-history":[{"count":5,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/posts\/2313\/revisions"}],"predecessor-version":[{"id":2404,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/posts\/2313\/revisions\/2404"}],"wp:attachment":[{"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/media?parent=2313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/categories?post=2313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/tags?post=2313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}