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:
- P: period
- Y: years
- M: months
- D: days
- T: time
- H: hours
- M: minutes
- S: seconds
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:
||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 PHP
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 );
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 );
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.
DateTime class has three methods that work with a
sub will modify a
DateTime object by a
diff will compare two
DateTime objects and return a
$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
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).
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, the
DateInterval::format method interprets
%a as total days while
strftime interprets it as a textual representation of the day (i.e. "Sun").
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
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.