I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 636 posts at DZone. You can read more from them at their website. View Full User Profile

Date and time in PHP 5

11.30.2010
| 10229 views |
  • submit to reddit

PHP is widely considered a procedural language. It was born this way, and it evolved by retrofitting object-oriented goodness into its core.
However, PHP has made consistent progress in object-orientation. With PHP 5, object passing by handler instead of copy and scope modifiers (public, private protected) for methods and variables have been introduced, along with interfaces and abstract classes. PHP as a language does not lack any fundamental construct of pure object-oriented languages like Java.

However, a language's support for OO is not limited to the syntax: native classes are the key to adopt OO without having to wrap every single primitive function or reinvent the wheel. Think about what would have Java been without its Collections Framework: these missing features of PHP are sometimes taken care of by userland frameworks.

PHP has made some progress here as well, for example with the Standard Php Library and its interfaces. Though, the SPL is incomplete and oriented to performance more than to object-oriented programming: take a look at the SplStack and SplQueue implementation containing 20 different methods to get the idea.

However a little gem is shipped with each PHP installation: the datetime extension, which contains the DateTime class and its siblings. Ideally, everything you can do with date_* functions, you can do it with this class.

Here are some code samples on how to use DateTime proficiently: this will be a code-intensive article. Some features are only available from PHP 5.3, like the DateInterval class.

<?php

class DateTimeTest extends PHPUnit_Framework_TestCase
{
public function testSupportsAdditionfDays()
{
$date = new DateTime('2010-11-26');
$date->add(new DateInterval('P15D')); // Period of 15 Days
$this->assertEquals('2010-12-11', $date->format('Y-m-d'));
}

public function testSupportsSubtractionOfMonths()
{
$date = new DateTime('2010-11-26');
$date->sub(new DateInterval('P20M')); // Period of 15 Days
$this->assertEquals('2009-03-26', $date->format('Y-m-d'));
}

// takes into account leap years, number of days of the month, etc.
public function testSupportsDifferenceOfDates()
{
$stopDate = new DateTime('2010-11-26');
$startDate = new DateTime('2010-10-28');
$duration = $stopDate->diff($startDate);
$this->assertEquals('29', $duration->format('%d'));
}

// never use mktime() again
public function testSupportsAlsoTimeAndOperatorOverloading()
{
$datetime = new DateTime('2010-11-26 12:00');
$this->assertTrue($datetime > new DateTime('2010-11-26 11:00'));
$this->assertTrue($datetime == new DateTime('2010-11-26 12:00'));
$this->assertTrue($datetime < new DateTime('2010-11-26 13:00'));
}
}
As you see in the code above, other than DateTime there are other classes like DateTimeZone (which name speaks for itself), DateInterval (representing a fixed amount of time) and DatePeriod (representing instead two fixed dates). The combination of these classes handles nearly every scenario of the typical PHP application, which want a datetime extension that works and do not get in the way of the rest of the business logic, forcing for example the developers to implement timezone handling. PHP has a wonderful datetime library, which takes into account regional timezones (not GMT+1 but Europe/Rome), leap years, and everything you can think of. And it's object-oriented: no excuses to roll out your own date management code.

You want something even cooler? Doctrine 2 has a type defined into its DBAL component which maps a DateTime field of an object to a date or datetime column in the database. This means you can create objects like this:
class User
{
/**
* @var DateTime
* @Column(type="datetime")
*/
private $lastLogin;

/**
* You will never have a broken date time string in your domain
* classes again. The type hinting will take care of that.
*/
public function setLastLogin(DateTime $lastLogin)
{
$this->lastLogin = $lastLogin;
}
// ...
}

and still use the Orm seamlessly, even if the variable is not a string or another primitive type, which are the typical variables required by ORMs to simplify the mapping.

I'm not proposing to scatter a primitive object into all of your domain classes, but it's better than a string to store a complex value like a Date. You can always wrap a DateTime object, possibly with other fields, when you feel a concept is missing:

class BirthDay
{
/**
* @var DateTime
private $date;

/**
* @var string
*/
private $personName;

public function howOld(DateTime $currentDate)
{
// ...
}
}
DateTime is an example of how PHP is a batteries-included language, finally with features natively available in an object-oriented Api instead of in a bunch of disconnected C-like functions.
Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)