An Introduction to the PHP DateInterval Class:
Date and time manipulation is an unavoidable part of programming; there will inevitably be a part of a project that requires a date to be modified. While, on the surface, echoing a date in the future brings a small bit of accomplishment, it can be quickly eradicated when one is tasked with manipulating that date.
Without being aware of the arsenal of tools PHP provides you with regards to working with dates, you might find yourself writing kludges that convert strings into timestamps for various comparisons.
Today we’re going to dissect the PHP DateInterval class, a power tool for dealing with dates in a web app.
But before learning about the DateInterval
object, one needs to first understand what an interval is.
What is an Interval?
Simply put, an interval is a duration of time.
When we converse about the topic of duration, we wouldn’t say, "Honey, I’ll be home on Dec 3rd, 2015 15:19pm".
Instead, we would simplify and say "I’ll be home in 5 minutes". Although this is ideal when conversing with another person, this is not so great as a data construct.
So how do we define "in 5 minutes" for a web app?
Fortunately, there’s an ISO for that.
ISO 8601 is the international standard that defines how to use, store, and transfer date, time, and duration information.
The specific string to define durations is an easy-to-remember pattern:
PYMDTHMS
- P: period
- Y: years
- M: months
- D: days
- T: time
- H: hours
- M: minutes
- S: seconds
Except for P
, each designator is optional.
Immediately preceding each designator is the quantity of time you want to store.
Below is a table showing samples of different date and time ranges:
String | Equivalent to… |
P1Y | 1 year |
P1M | 1 month |
P1D | 1 day |
P30D | 30 days |
PT1H | 1 hour |
PT5M | 5 minutes |
PT35S | 35 seconds |
P1Y6M29DT4H34M23S | 1 year, 6 months, 29 days, 4 hours, 34 minutes, 23 seconds |
Creating a DateInterval Object
Now that we understand what an interval is — it’s simply a duration of time — and that ISO 8601 defines our duration’s format, we can start playing around with the PHPDateInterval
class.
Let’s define a predictable duration, create a DateInterval
object, and output the result to the screen.
We’ll start with "1 year, 2 months, 3 days, 4 hours, 5 minutes, 6 seconds".
$Duration = new DateInterval( "P1Y2M3DT4H5M6S" );
print_r( $Duration );
Result:
DateInterval Object
(
[y] => 1
[m] => 2
[d] => 3
[h] => 4
[i] => 5
[s] => 6
...
)
You will notice that the constructor for the DateInterval
class has parsed your duration and stored the individual values in its own properties. $Duration->y
matches the 1Y
from the duration string you passed in.
Let’s try another more practical duration: 1 month. You’ll notice that any undefined durations are automatically defaulted to 0.
$Duration = new DateInterval( "P1M" );
print_r( $Duration );
Result:
DateInterval Object
(
[y] => 0
[m] => 1
[d] => 0
[h] => 0
[i] => 0
[s] => 0
...
)
So now we know what’s happening, but what do we really have? What’s so great and tangible about this?
The real benefit to what we have here is that the $Duration
object itself represents a duration of time. We don’t need to know a source or destination date; $Duration
is simply 1 month.
Note: It’s important to note that creating a DateInterval
with 13 months (P13M
) will not roll over and provide you with "1 year 1 month".
That makes sense because we don’t have a source or destination date. Imagine the case of 61 days:
- On October 1, it’s 2 months
- On December 1, it’s only 1 month and 30 days
- On February 1, it’s 2 months and 2 days (or only 2 months and 1 day on leap years)
Manipulating Dates with Durations
Durations tame the manipulation of PHP DateTime objects.
The PHP DateTime
class has three methods that work with a DateInterval
object:
Both add
and sub
will modify a DateTime
object by a DateInterval
, while diff
will compare two DateTime
objects and return a DateInterval
.
$Now = new DateTime();
echo $Now->format('Y-m-d'); // 2014-06-12
$Duration = new DateInterval('P1M'); // 1 month
$Now->add( $Duration );
echo $Now->format('Y-m-d'); // 2014-07-12
$Duration = new DateInterval('P2M'); // 2 months
$Now->sub( $Duration );
echo $Now->format('Y-m-d'); // 2014-05-12
In the above example you can see how date manipulation becomes much easier and more predictable by using DateInterval
objects to modify DateTime
objects.
The diff
method is just as easy to use, but provides an extra piece of information:total days. This is important because when using the DateTime
object to find a difference, we have a source and destination date, and therefore we can reduce the units of time into larger denominations. However, having the total number of days in between is a valuable piece of information.
$Year = new DateInterval('P1Y');
echo $Year->days; // 0
$Date1 = new DateTime();
$Date2 = new DateTime();
$Date2->add( $Year );
$Difference = $Date1->diff( $Date2 );
echo $Difference->days; // 365
Reading Durations and Extracting Intervals
There are inevitably going to be times where you want to extract portions of the stored interval (much the same as you would a date).
The DateInterval
class has a handy format
method. PHP docs has a table for the format method that is a useful reference.
You use the format
method like this:
$Duration = new DateInterval('P345D');
echo $Duration->format('I am %d days'); // I am 345 days
Note: It’s important to note, for those familiar with the strftime
method, that the recognized characters are completely different. For example, theDateInterval::format
method interprets %a
as total days while strftime
interprets it as a textual representation of the day (i.e. "Sun").
Oddly enough, DateInterval
doesn’t natively have a way to extract the entire interval spec without the zero values. This leaves you with two options:
- Extract it with 0 elements, which is perfectly acceptable
- Extend the
DateInterval
class
The second option, extending the DateInterval
class, brings upon it’s own difficulties that we won’t touch on here today.
To extract the interval spec with the 0 elements intact, you can use the same format method like so:
$Duration = new DateInterval('P345D');
echo $Duration->format('P%yY%mM%dDT%hH%iM%sS'); // P0Y0M345DT0H0M0S
If you want to confirm the above, simply create a new DateInterval
with the result of the first:
$interval_spec = 'P345D';
$Duration1 = new DateInterval( $interval_spec );
echo $Duration1->format('%d'); // 345
$interval_spec = $Duration1->format('P%yY%mM%dDT%hH%iM%sS'); // P0Y0M345DT0H0M0S
$Duration2 = new DateInterval( $interval_spec );
echo $Duration2->format('%d'); // 345
You should now have a grasp on using the PHP DateInterval
class, and it’s capabilities.
Hopefully you’re able to apply this current and future web app projects.