I was sitting writing a kind of helpdesk call management program in PHP and found that I needed to work out how much time had elapsed since somebody had last bothered to contact the client about their problem. In the past, when I used to use ASP, the solution was simple - ASP has a command called DateDiff which takes two dates and can tell you how many seconds has passed between them, how many days, months and so on. After scouring the PHP manual for a while I decided that PHP has no such beast. I then wondered how many other people there were out there like me, and thus this tutorial.
Ok, so what are we going to cover?
  1. Getting the current date and time - what options do we have ?
  2. Changing the way the date is displayed - date and time formatting
  3. Converting existing dates into Unix timestamps
  4. Back to the future - modifying the date
    1. Adding time to the current date
    2. Subtracting time from the current date
    3. Working out the time between two dates
  5. Creating a DateAdd function for PHP
  6. Creating a DateDiff function for PHP

Getting the current date and time

The way that Unix machines tell the time is by counting the number of seconds that have elapsed since Midnight 1 January 1970. They call this the Unix Epoch.
So if we had a piece of PHP that looked something like this:

<?php

echo time();

?>
it would return to me a result of
958905820
This just happens to be about 12h43 on Sunday 21 May 2000.
This is all well and good you may say, but how does that help me ? Well quite a bit actually. A lot of the functions that do date manipulation in PHP require the timestamp that is returned by the time() function as one of the inputs. Also, since PHP uses the timestamp in the same way under both Unix and Windows, it allows you to use code on either operating system without any problems. A further bonus is that since the time() function is returning an integer, you can store it as such in a database or text file - no more need for fancy date/time database fields.
OK, so now that you have the how and why about Unix timestamps, let's get on to the really important bits and start using it for something useful.

Changing the way the date is displayed - date and time formatting

PHP supplies you with 2 ways of turning the Unix timestamp into something useful. The first one is a function called date(). This function takes two arguments - a string that lays out the formatting that you want returned, the second the Unix timestamp. The formatting string is simply some special characters that display those parts of the date and time that you want in the format that you want it. Suppose you wanted the date to be displayed as "18h01 Sunday 21 May"
We will need to use one of the special characters for each of the changing bits in the string- you can look these up in the PHP manual under function.date.html. There's a fair number of these characters and they will return things like the day of the week, month name, year in 2 and 4 digit format, whether it AM or PM and many others. The ones that we will need for this example are:
'H'which returns the hour of the day in 24-hour format
'i'which will return the minutes
'l'which will return the day of the week (long form)
'd'which returns the day of the month and
'F'the full month name
So our string will look something like "Hhi l d F", and our PHP a bit like:

<?php

echo date'Hhi l d F'time() );

?>
When we run this though, we find that we actually get the result of
180609 Sunday 21 May
which seems a bit curious until we have a look at the PHP manual and find that the lowercase h stands for the hour in 12 hour format. So once again, the old saying of "A computer does what you tell it to do, not what you want it to do" rings true. We have two options here. The first is to escape the lowercase h and have this:

<?php

echo date'H\hi l d F'time() );

?>
which gives us the result:
18h12 Sunday 21 May
This is great, but what happens if we want to include some date and time info into a more complicated sentence? Do we have to escape every character? No, we use a different function, one called strftime().
strftime() brings with it 2 advantages. The first which we are not going to cover here is that if you have used the setlocale() function, you can have strftime bring the month names up in the correct language. The other advantage is that you can embed your specially formatted date and time info into free-form strings. This does mean however that if you went and learned all of the special characters for the date() function, you get to learn a whole set of different ones now.
The way that strftime() works is exactly the same as date(), except that the special characters have the percent sign % in front of them. So the previous example in strftime() would look like

<?php

echo strftime'%Hh %M %A %d %b'time() );

?>
which gives us:
18h24 Sunday 21 May
This may seem a trifle more complicated, but imagine what you actually wanted to say was "Today is Sunday 21 May 2000. The time is somewhere close to 18h24." Using the date command in this instance would be a bit annoying I think.
Earlier I mentioned that there were 2 ways of getting something useful out of the Unix timestamp. We've just seen date() and strftime(). The other is getdate(). This function only needs the Unix timestamp as an argument and it returns an associative array of the elements in the date.
As an example:

<?php

$date_time_array 
getdatetime() );
echo 
$date_time_array['weekday'];

?>
will return:
Sunday
Besides "weekday", the other parts of the array are:
"seconds"seconds
"minutes"minutes
"hours"hours
"mday"day of the month
"wday"day of the week as a number
"mon"month as a number
"year"year
"yday"day of the year as a number
"month"full month name
So now we can create readable dates and times. But what about going the other way ?

Converting existing dates into Unix timestamps

Often you may have to work with data that is already in some sort of date and time format. I opened a clients Microsoft Access database now and found that the dates are all stored in the format YYYY/MM/DD, so inserting the current date would give me 2000/05/27. The mktime() function can take the values of parts of a date and turn them into a Unix timestamp.
The format of the function is:
int mktime(int hour, int minute, int second, int month, int day, int year, int [is_dst] );
From the left you provide the hour, minute, second, month, day and year. The last argument specifies whether you are in daylight savings time or not. It is optional and so to keep things simple we will leave it out.
The script will look something like this:

<?php

echo mktime0,0,0,5,27,2000 );

?>
I've put in zeros for the hour, minute and seconds since we don't know them and you have to put something in there. Putting in zeros will give us midnight, which is fine. Of course you're probably pointing out right now that I've cheated and gone and put the numbers in there myself, which is true, so let's do it again, this time by making the script work out what to put into where:

<?php

$access_date 
'2000/05/27';

// The explode() function splits a string by another string. In this case $access_date is
// split on the / 
 
$date_elements  explode("/",$access_date);

// at this point
// $date_elements[0] = 2000
// $date_elements[1] = 5
// $date_elements[2] = 27

echo mktime(0,0,0,$date_elements[1],$date_elements[2],$date_elements[0]);
?>
Right, let's get a bit more complex and imagine that instead of just getting back the date from the Access database, we got the date and time in this format:
2000/05/27 02:40:21 PM

<?php

// the string we get from Access
$date_time_string '2000/05/27 02:40:21 PM';
// Split the string into 3 parts 
datetime and AM/PM 
$dt_elements 
explode(' ',$date_time_string);
// Split the date up
$date_elements explode('/',$dt_elements[0]);

// Split the time up
$time_elements =  explode(':',$dt_elements[1]);

// If we have a PM then we can add 12 hours to the hour to get into 24 hour time.
if ($dt_elements[2]=='PM'
{
    
$time_elements[0]+=12;
}

// output the result
echo mktime($time_elements[0],
$time_elements[1],$time_elements[2],
$date_elements[1],$date_elements[2],
$date_elements[0]);

?>

Modifying the date

Often we will want to know what the time will be in 6 hours time, what the date was 35 days ago or how many seconds it has been since you last played Quake3. We've already seen how the mktime() function can be used to generate a unix timestamp from individual date and time elements. If we wanted to create a unix timestamp out of the current date and time, how would we go about it ? A bit of a pointless exercise, but it will help to illustrate what we will be doing later.
As we have seen, mktime() takes the following arguments: hour, minute, second, month, day, year. And if you recall from way back in section 2, we saw that the getdate() function can get all those bits and pieces for us.

<?php

// get the current timestamp into an array 
$timestamp time();
echo 
$timestamp;
echo 
'&lt;p&gt;';
$date_time_array getdate($timestamp);

// use mktime to recreate the unix timestamp
$timestamp mktime(
    
$date_time_array['hours'],
    
$date_time_array['minutes'],
    
$date_time_array['seconds'],
    
$date_time_array['mon'],
    
$date_time_array['mday'],
    
$date_time_array['year']
    );
echo 
$timestamp;
?>
Looks a little bit confusing, so what I'll do is add in a couple of variables so that things make a little bit more sense.

<?php

// get the current timestamp into an array
$timestamp time();
echo 
$timestamp;
echo 
'&lt;p&gt;';
$date_time_array getdate($timestamp);

$hours $date_time_array['hours'];
$minutes $date_time_array['minutes'];
$seconds $date_time_array['seconds'];
$month $date_time_array['mon'];
$day $date_time_array['mday'];
$year $date_time_array['year'];

// use mktime to recreate the unix timestamp
$timestamp mktime($hours,$minutes,$seconds,$month,$day,$year);
echo 
$timestamp;

?>
Now that we've taken the info out of the array that was created by getdate() and into appropriately named variables, the code is a bit easier to read and understand. The great thing now is that if we wanted to add 19 hours to the current date, instead of feeding $hours to mktime(), we can just feed it $hours +19. mktime() will do the automatic rollover to the next day for us!

<?php

// get the current timestamp into an array
$timestamp time();
echo 
strftime('%Hh%M %A %d %b',$timestamp);
echo 
'&lt;p&gt;';
$date_time_array getdate($timestamp);

$hours $date_time_array['hours'];
$minutes $date_time_array['minutes'];
$seconds $date_time_array['seconds'];
$month $date_time_array['mon'];
$day $date_time_array['mday'];
$year $date_time_array['year'];

// use mktime to recreate the unix timestamp
// adding 19 hours to $hours
$timestamp mktime($hours 19,$minutes,$seconds,$month,$day,$year);
echo 
strftime('%Hh%M %A %d %b',$timestamp);
echo 
'&lt;br&gt;~E after adding 19 hours';

?>
Running this now gives me:
14h58 Saturday 03 Jun
09h58 Sunday 04 Jun
~E after adding 19 hours
Subtracting time is done in exactly the same way - just subtract the amount of time you want from the relevant variable.
Working out the difference between two times is also pretty straightforward. All you need to do is have both converted into unix timestamps and you just subtract the one from the other. The difference will be the difference between the two times in seconds. Some quick arithmetic can convert the seconds into days, hours, minutes and seconds.

Creating a DateAdd function for PHP

As I said in the beginning - the reason for this tutorial was because I could find no function in PHP that was similar to ASP's DateDiff function. So after explaining how PHP handles date and time I though it would be cool if we ported two commonly used ASP date functions to PHP. The first one is the DateAdd function.
The DateAdd function, according the VBScript documentation I have, "Returns a date to which a specified time interval has been added."
The syntax is DateAdd (interval,number,date).
The interval is a string expression that defines the interval you want to add. For example minutes or days, the number is the number of that interval that you wish to add, and the date is the date.
Interval can be one of:
yyyyyear
qQuarter
mMonth
yDay of year
dDay
wWeekday
wwWeek of year
hHour
nMinute
sSecond

 
As far as I can tell, w,y and d do the same thing, that is add 1 day to the current date, q adds 3 months and ww adds 7 days. If I've missed some subtlety of VBScript, someone please let me know :)

<?php

function DateAdd($interval$number$date) {

    
$date_time_array getdate($date);
    
$hours $date_time_array['hours'];
    
$minutes $date_time_array['minutes'];
    
$seconds $date_time_array['seconds'];
    
$month $date_time_array['mon'];
    
$day $date_time_array['mday'];
    
$year $date_time_array['year'];

    switch (
$interval) {
    
        case 
'yyyy':
            
$year+=$number;
            break;
        case 
'q':
            
$year+=($number*3);
            break;
        case 
'm':
            
$month+=$number;
            break;
        case 
'y':
        case 
'd':
        case 
'w':
            
$day+=$number;
            break;
        case 
'ww':
            
$day+=($number*7);
            break;
        case 
'h':
            
$hours+=$number;
            break
        case 
'n':
            
$minutes+=$number;
            break;
        case 
's':
            
$seconds+=$number
            break;            
    }
       
$timestampmktime($hours,$minutes,$seconds,$month,$day,$year);
    return 
$timestamp;
}

?>
We can save that code in a file called dateadd.inc and then execute the following code:

<?php

include('dateadd.inc'); $temptime time();
echo 
strftime('%Hh%M %A %d %b',$temptime);
$temptime DateAdd('n',50,$temptime);
echo 
'&lt;p&gt;';
echo 
strftime('%Hh%M %A %d %b',$temptime);

?>
which will return to us:

15h41 Saturday 03 Jun
16h31 Saturday 03 Jun

Creating a DateDiff function for PHP

OK, so that's DateAdd out of the way. What about DateDiff now ?
DateDiff, according to the documentation, "Returns the number of intervals between two dates."
The syntax is DateDiff(interval,date1,date2).
The intervals that it uses are the same as those that we saw in the DateAdd function. For the sake of simplicity we're going to gloss over a number of elements of VBScipt's DateDiff function that would otherwise complicate matters. In this example the optional arguments to DateDiff (that is whether the week starts on a Monday or a Sunday) are not used. The intervals that we are going to allow are going to be "w", "d&q, "h", "n" and "s".
Let's see what we can come up with:

<?php

Function DateDiff
($interval,$date1,$date2) {
    
// get the number of seconds between the two dates 
$timedifference $date2 $date1;

    switch (
$interval) {
        case 
'w':
            
$retval bcdiv($timedifference,604800);
            break;
        case 
'd':
            
$retval bcdiv($timedifference,86400);
            break;
        case 
'h':
            
$retval =bcdiv($timedifference,3600);
            break
        case 
'n':
            
$retval bcdiv($timedifference,60);
            break;
        case 
's':
            
$retval $timedifference;
            break;
            
    }
    return 
$retval;

}
?>
Save that code to datediff.inc and you can try the following code:

<?php

include('datediff.inc';
include(
'dateadd.inc');
$currenttime time();
echo 
'Current time: '.strftime('%Hh%M %A %d %b',$currenttime).'&lt;br&gt;';
$newtime DateAdd
('n',50,$currenttime);
echo 
'Time plus 50 minutes: '.
strftime('%Hh%M %A %d %b',$newtime).'&lt;br&gt;';
$temptime DateDiff('n',$currenttime,$newtime);
echo 
'Interval between two times: '.$temptime;

?>
which, if you've got everything set up properly, should return:
Current time: 16h23 Saturday 03 Jun
Time plus 50 minutes: 17h13 Saturday 03 Jun
Interval between two times: 50
If you are running PHP on a unix system, you will have to compile in support for the bcmath functions. README.BCMATH in your PHP distribution gives you the full details. PHP4 for Windows can do bcmath calculations without any special tinkering.
That's it then for dates. You should now have all the tools you need to tackle dates and times and their practical application in PHP
--Allan