Understanding PHP DateTime

Handling the date and time in a program is not as straightforward as it may seem. Months can have a different number of days, and leap years add a day depending on the year. Then there are leap seconds from time to time, in order to correct for the earth’s rotation slowing due to tidal drag. Furthermore, timezones and daylight savings time create more issues based on location and cause time to repeat.

When I built the first version of ScheduleFire it used a custom system for handling data and time. I stored dates and times in the database in a custom format and handled them in a very complex way. It had to be complex because date and time are very complex. For timezones, it simply didn’t handle them. This was a simple solution, but it meant that every account using scheduling had to have all of its users use the same timezone.

There is a better way

PHP has a DateTime class that is built to handle the complexities of time. I will show you how simple it is to use and provide some examples for real world usage. This simple program will take a date and time as input, then it will show a simple weekly calendar.

<?php
//datetime.php
$input_date = null;
if($input_date = $_GET['input_date']){
o$datetime = new DateTime($input_date);
o
oecho 'Event Date and Time: '.$datetime->format('m/d/Y H:i:s');
oecho "<br>";
o
o$event_datetime = clone $datetime;
o$datetime->modify('previous sunday');
o$end_datetime = clone $datetime;$end_datetime->modify('+ 1 week');

o$style = '<style>.calendar td{border:solid 1px;}</style>';
o$calendar = '<table class="calendar"><tr>';
odo{
o$calendar .= '<td>';
oif($event_datetime->format('m/d/Y') == $datetime->format('m/d/Y')){
o$calendar .= '**';
o}
o$calendar .= $datetime->format('l, dS');
o$calendar .= '</td>';
o$datetime->modify('+ 1 day');
o}while($datetime->getTimestamp() < $end_datetime->getTimestamp());
o$calendar .= '</tr></table>';
oecho $calendar;
oecho $style;
}
$form = <<<HTML
<form>
<br>
Event Date and Time<br>
<input type="date" name="input_date" value="$input_date"/>
<br>
<input type="submit" value="Submit"/>
</form>
HTML;
echo $form;

datettime

On line 5 we are creating our DateTime object by passing in the time that we want to have represented. Leave this blank to get the current time.

For this example we clone the object twice to represent the time selected, the time at the end of the week, and the time at the beginning of the week (which is used as the current time in the loop).

The modify() method on line 11 provides a simple way to adjust the time from its current position. If you try something like $nextyear_datetime = $current_datetime->modify('+ 1 year'); you will notice that both of your DateTime objects are at the same time next year. If you want to use this type of syntax then check out DateTimeImmutable (PHP 5.5.0).

Finally the format() method on line 7 returns the time in any valid PHP date/time format.

Handling timezones

This is the simple explanation of DateTime, providing most of the important functionality without having to learn the rest. Timezones are not addressed above so we will rebuild this with respect to timezone.

<?php
//datetimezone.php
$input_date = null;
$tz_ids = DateTimeZone::listIdentifiers();
if($input_date = $_GET['input_date']){

o$tz = new DateTimeZone($tz_ids[$_GET['timezone']]);
o$datetime = new DateTime($input_date,$tz);
o$event_datetime = clone $datetime;
o
o
oecho 'Event Date and Time: '.$event_datetime->format('m/d/Y H:i:s');
oecho "<br>";
oecho 'Timezone: '.$tz->getName();
oecho "<br>";
o
o$datetime->modify('previous sunday');
o$end_datetime = clone $datetime;$end_datetime->modify('+ 1 week');

o$style = '<style>.calendar td{border:solid 1px;}</style>';
o$calendar = '<table class="calendar"><tr>';
odo{
o$calendar .= '<td>';
oif($event_datetime->format('m/d/Y') == $datetime->format('m/d/Y')){
o$calendar .= '**';
o}
o$calendar .= $datetime->format('l, dS');
o$calendar .= '</td>';
o$datetime->modify('+ 1 day');
o}while($datetime->getTimestamp() < $end_datetime->getTimestamp());
o$calendar .= '</tr></table>';
oecho $calendar;
oecho $style;
o
o$utc_tz = new DateTimeZone('UTC');
o$event_datetime->setTimezone($utc_tz);
oecho '<br>';
oecho 'UTC Event Date and Time: '.$event_datetime->format('m/d/Y H:i:s');
}
$tz_options = '';

foreach($tz_ids as $key=>$tz_opt){
oif($_GET['timezone'] == $key){$selected = ' selected';}else{$selected = '';}
o$tz_options .= '<option value='.$key.$selected.'>'.$tz_opt.'</option>';
}
$form = <<<HTML
<form>
<br>
Event Date and Time<br>
<input type="date" name="input_date" value="$input_date"/>
<select name="timezone">$tz_options</select>
<br>
<input type="submit" value="Submit"/>
</form>
HTML;
echo $form;

datettimezoneNotice the new timezone selector, which gets its options from DateTimeZone::listIdentifiers();

We use these options to create a DateTimeZone object on line 7 and pass that object into the DateTime constructor on line 8. Now DateTime knows that the time it was given is in the timezone. The output will always assume that you are still expecting that timezone unless you use the setTimezone() method, line 36.

DateTime has a method to return the timestamp for the time selected. DateTime::getTimestamp();

This method will ALWAYS return UTC time, regardless of the timezone setting. This is intentional and it can be very helpful for handling times in a more absolute way. It is also useful if you prefer to handle timezones in the application and use the numeric timestamp when storing times in the database.

This is all you need to know about DateTime but it is well worth being familiar with the other functions that DateTime offers, and some other related classes like DateInterval and DatePeriod.

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *