21 Managing the Date and Time

IN THIS CHAPTER, WE DISCUSS CHECKING AND FORMATTING the date and time and converting between date formats. These capabilities are especially important when you are converting between MySQL and PHP date formats, Unix and PHP date formats, and dates entered by the user in an HTML form.

Key topics covered in this chapter include

Image  Getting the date and time in PHP

Image  Converting between PHP and MySQL date formats

Image  Calculating dates

Image  Using the calendar functions

Getting the Date and Time from PHP

Way back in Chapter 1, “PHP Crash Course,” we described using the date() function to get and format the date and time from PHP. Here, we discuss this function and some of PHP’s other date and time functions in a little more detail.

Using the date( ) Function

As you might recall, the date() function takes two parameters, one of them optional. The first one is a format string, and the second, optional one is a Unix timestamp. If you don’t specify a timestamp, date() will default to the current date and time. It returns a formatted string representing the appropriate date.

A typical call to the date() function could be

echo date('jS F Y'),

This call produces a date in the format 19th June 2008. The format codes accepted by date() are listed in Table 21.1.

Table 21.1  Format Codes for PHP’s date() Function

Image

Image

Dealing with Unix Timestamps

The second parameter to the date() function is a Unix timestamp. In case you are wondering exactly what this means, most Unix systems store the current time and date as a 32-bit integer containing the number of seconds since midnight, January 1, 1970, GMT, also known as the Unix Epoch. This concept can seem a bit esoteric if you are not familiar with it, but it’s a standard and integers are easy for computers to deal with.

Unix timestamps are a compact way of storing dates and times, but it is worth noting that they do not suffer from the year 2000 (Y2K) problem that affects some other compact or abbreviated date formats. They do have similar problems, though, because they can represent only a limited span of time using a 32-bit integer. If your software needs to deal with events before 1902 or after 2038, you will be in trouble.

On some systems including Windows, the range is more limited. A timestamp cannot be negative, so timestamps before 1970 cannot be used. To keep your code portable, you should bear this fact in mind.

You probably don’t need to worry about your software still being used in 2038. Timestamps do not have a fixed size; they are tied to the size of a C long, which is at least 32 bits. If your software still happens to be in use in 2038, it is exceedingly likely that your system will be using a larger type by that time.

Although this is a standard Unix convention, this format is still used by date() and a number of other PHP functions even if you are running PHP under Windows. The only difference is that, for Windows, the timestamp must be positive.

If you want to convert a date and time to a Unix timestamp, you can use the mktime() function. It has the following prototype:

int mktime ([int hour[, int minute[, int second[, int month[,
            int day[, int year [, int is_dst]]]]]]])

The parameters are fairly self-explanatory, with the exception of the last one, is_dst, which represents whether the date was in daylight savings time. You can set this parameter to 1 if it was, 0 if it wasn’t, or -1 (the default value) if you don’t know. In the case of using -1, PHP will try to figure it out based on the system it is running on. This parameter is optional, so you will rarely use it anyway.

The main trap to avoid with this function is that the parameters are in a fairly unintuitive order. The ordering doesn’t lend itself to leaving out the time. If you are not worried about the time, you can pass in 0s to the hour, minute, and second parameters. You can, however, leave out values from the right side of the parameter list. If you don’t provide parameters, they will be set to the current values. Hence, a call such as

$timestamp = mktime();

returns the Unix timestamp for the current date and time. You could also get this result by calling

$timestamp = time();

The time() function does not take any parameters and always returns the Unix timestamp for the current date and time.

Another option is the date() function, as already discussed. The format string "U" requests a timestamp. The following statement is equivalent to the two previous ones:

$timestamp = date("U");

You can pass in a two- or four-digit year to mktime(). Two-digit values from 0 to 69 are interpreted as the years 2000 to 2069, and values from 70 to 99 are interpreted as 1970 to 1999.

Here are some other examples to illustrate the use of mktime():

$time = mktime(12, 0, 0);

gives noon on today’s date.

$time = mktime(0,0,0,1,1);

gives the 1st of January in the current year. Note that 0 (rather than 24) is used in the hour parameter to specify midnight.

You can also use mktime() for simple date arithmetic. For example,

$time = mktime(12,0,0,$mon,$day+30,$year);

adds 30 days to the date specified in the components, even though ($day+30) will usually be bigger than the number of days in that month.

To eliminate some problems with daylight savings time, use hour 12 rather than hour 0. If you add (24 * 60 * 60) to midnight on a 25-hour day, you’ll stay on the same day. Add the same number to midday, and it’ll give 11am but will at least be the right day.

Using the getdate( ) Function

Another date-determining function you might find useful is getdate(). This function has the following prototype:

array getdate ([int timestamp])

It takes an optional timestamp as a parameter and returns an array representing the parts of that date and time, as shown in Table 21.2.

Table 21.2  Array Key-Value Pairs from getdate() Function

Image

After you have these parts in an array, you can easily process them into any required format. The 0 element in the array (the timestamp) might seem useless, but if you call getdate() without a parameter, it will give you the current timestamp.

Using the getdate() function, the code

<?php
$today = getdate();
print_r($today);
?>

produces something similar to the following output:

Array (
[seconds] => 45
[minutes] => 6
[hours] => 20
[mday] => 14
[wday] => 3
[mon] => 3
[year] => 2007
[yday] => 72
[weekday] => Wednesday
[month] => March
[0] => 1173917205
)

Validating Dates with checkdate( )

You can use the checkdate() function to check whether a date is valid. This capability is especially useful for checking user input dates. The checkdate() function has the following prototype:

int checkdate (int month, int day, int year)

It checks whether the year is a valid integer between 0 and 32,767, whether the month is an integer between 1 and 12, and whether the day given exists in that particular month. The function also takes leap years into consideration when working out whether a day is valid.

For example,

checkdate(2, 29, 2008)

returns true, whereas

checkdate(2, 29, 2007)

does not.

Formatting Timestamps

You can format a timestamp according to the system’s locale (the web server’s local settings) using the strftime() function. This function has the following prototype:

string strftime ( string $format [, int $timestamp] )

The $format parameter is the formatting code that defines how the timestamp will be displayed. The $timestamp parameter is the timestamp that you pass to the function. This parameter is optional. If no timestamp is passed as a parameter, the local system timestamp (at the time the script is run) is used. For instance, the following code

<?php
 echo strftime('%A<br />'),
 echo strftime('%x<br />'),
 echo strftime('%c<br />'),
 echo strftime('%Y<br />'),
 ?>

displays the current system timestamp in four different formats. This code will produce output similar to the following:

     Friday

     03/16/07

     03/16/07 21:17:24

     2007

The complete list of formatting codes for strftime() is listed in Table 21.3.

Table 21.3  Formatting Codes for strftime()

Image

It is important to note that whenever it says standard format in Table 21.3, the formatting code gets replaced by the associated value according to the web server’s local settings. The strftime() function is very useful for displaying dates and times in a variety of different ways to make your pages more user friendly.

Converting Between PHP and MySQL Date Formats

Dates and times in MySQL are handled in ISO 8601 format. Times work relatively intuitively, but ISO 8601 requires you to enter dates with the year first. For example, you could enter March 29, 2008, either as 2008-03-29 or as 08-03-29. Dates retrieved from MySQL are also in this format by default.

Depending on your intended audience, you might not find this function very user friendly. To communicate between PHP and MySQL, then, you usually need to perform some date conversion. This operation can be performed at either end.

When putting dates into MySQL from PHP, you can easily put them into the correct format by using the date() function, as shown previously. One minor caution if you are creating them from your own code is that you should store the day and month with leading zeros to avoid confusing MySQL. You can use a two-digit year, but using a four-digit year is usually a good idea. If you want to convert dates or times in MySQL, two useful functions are DATE_FORMAT() and UNIX_TIMESTAMP().

The DATE_FORMAT() function works similarly to the PHP function but uses different formatting codes. The most common thing you want to do is format a date in normal American format (MM-DD-YYYY) rather than in the ISO format (YYYY-MM-DD) native to MySQL. You can do this by writing your query as follows:

SELECT DATE_FORMAT(date_column, '%m %d %Y')
FROM tablename;

The format code %m represents the month as a two-digit number; %d, the day as a two-digit number; and %Y, the year as a four-digit number. A summary of the more useful MySQL format codes for this purpose is shown in Table 21.4.

Table 21.4  Format Codes for MySQL’s DATE_FORMAT() Function

Image

The UNIX_TIMESTAMP function works similarly but converts a column into a Unix timestamp. For example,

SELECT UNIX_TIMESTAMP(date_column)
FROM tablename;

returns the date formatted as a Unix timestamp. You can then do as you want with it in PHP.

You can easily perform date calculations and comparisons with the Unix timestamp. Bear in mind, however, that a timestamp can usually represent dates only between 1902 and 2038, whereas the MySQL date type has a much wider range.

As a rule of thumb, use a Unix timestamp for date calculations and the standard date format when you are just storing or showing dates.

Calculating Dates in PHP

A simple way to work out the length of time between two dates in PHP is to use the difference between Unix timestamps. We use this approach in the script shown in Listing 21.1.

Listing 21.1  calc_age.php—Working Out a Person’s Age Based on Birthdate


<?php
 // set date for calculation
 $day = 18;
 $month = 9;
 $year = 1972;
 // remember you need bday as day month and year
 $bdayunix = mktime (0, 0, 0, $month, $day, $year); // get ts for then
 $nowunix = time(); // get unix ts for today
 $ageunix = $nowunix - $bdayunix; // work out the difference
 $age = floor($ageunix / (365 * 24 * 60 * 60)); // convert from seconds to years
 echo "Age is $age";
?>


This script sets the date for calculating the age. In a real application, it is likely that this information might come from an HTML form. The script begins by calling mktime() to work out the timestamp for the birthday and for the current time:

$bdayunix = mktime (0, 0, 0, $month, $day, $year);
$nowunix = time(); // get unix ts for today

Now that these dates are in the same format, you can simply subtract them:

$ageunix = $nowunix - $bdayunix;

Now, the slightly tricky part: converting this time period back to a more human-friendly unit of measure. This is not a timestamp but instead the age of the person measured in seconds. You can convert it back to years by dividing by the number of seconds in a year. You then round it down by using the floor() function because a person is not said to be, for example, 20, until the end of his twentieth year:

$age = floor($ageunix / (365 * 24 * 60 * 60)); // convert from seconds to years

Note, however, that this approach is somewhat flawed because it is limited by the range of Unix timestamps (generally 32-bit integers). Birthdates are not an ideal application for timestamps. This example works on all platforms only for people born from 1970 onward. Windows cannot manage timestamps prior to 1970. Even then, this calculation is not always accurate because it does not allow for leap years and might fail if midnight on the person’s birthday is the daylight savings switchover time in the local time zone.

Calculating Dates in MySQL

PHP does not have many date manipulation functions built in. Obviously, you can write your own, but ensuring that you correctly account for leap years and daylight savings time can be tricky. Another option is to download other people’s functions. You can find many as user-contributed notes in the PHP manual, but only some of them are well thought out.

An option that may not seem immediately obvious is using MySQL. MySQL provides an extensive range of date manipulation functions that work for times outside the reliable range of Unix timestamps. You need to connect to a MySQL server to run a MySQL query, but you do not have to use data from the database.

The following query adds one day to the date February 28, 1700, and returns the resulting date:

select adddate('1700-02-28', interval 1 day)

The year 1700 is not a leap year, so the result is 1700-03-01.

You can find an extensive syntax for describing and modifying dates and times described in the MySQL manual; it is located at http://www.mysql.com/doc/en/Date_and_time_functions.html.

Unfortunately, there is not a simple way to get the number of years between two dates, so the birthday example is still a little flaky. You can get a person’s age in days very easily, and Listing 21.2 converts that age to years imprecisely.

Listing 21.2  mysql_calc_age.php—Using MySQL to Work Out a Person’s Age Based on Birthdate


<?php
 // set date for calculation
 $day = 18;
 $month = 9;
 $year = 1972;
 // format birthday as an ISO 8601 date
 $bdayISO = date("c", mktime (0, 0, 0, $month, $day, $year));
 // use mysql query to calculate an age in days
 $db = mysqli_connect('localhost', 'user', 'pass'),
 $res = mysqli_query($db, "select datediff(now(), '$bdayISO')");
 $age = mysqli_fetch_array($res);
 // convert age in days to age in years (approximately)
 echo "Age is ".floor($age[0]/365.25);
?>


After formatting the birthday as an ISO timestamp, you pass the following query to MySQL:

select datediff(now(), '1972-09-18T00:00:00+10:00')

The MySQL function now() always returns the current date and time. The MySQL function datediff() (added at version 4.1.1) subtracts one date from another and returns the difference in days.

It is worth noting that you are not selecting data from a table or even choosing a database to use for this script, but you do need to log in to the MySQL server with a valid username and password.

Because no specific built-in function is available for such calculations, an SQL query to calculate the exact number of years is fairly complex. Here, we took a shortcut and divided the age in days by 365.25 to give the age in years. This calculation can be one year out if run on somebody’s birthday, depending on how many leap years there have been in that person’s lifetime.

Using Microseconds

For some applications, measuring time in seconds is not precise enough to be useful. If you want to measure very short periods, such as the time taken to run some or all of a PHP script, you need to use the function microtime().

In PHP 5, you should pass true to microtime(). When this optional parameter is provided, microtime() will return the time as a floating point value that is ready for whatever use you have in mind. The value is the same one returned by mktime(), time(), or date() but has a fractional component.

The statement

echo number_format(microtime(true), 10, '.', ' '),

produces something like 1174091854.84.

On older versions, you cannot request the result as a float. It is provided as a string. A call to microtime() without a parameter returns a string of this form "0.34380900 1174091816". The first number is the fractional part, and the second number is the number of whole seconds elapsed since January 1, 1970.

Dealing with numbers rather than strings is more useful, so in PHP 5 it is easiest to call microtime() with the parameter true.

Using the Calendar Functions

PHP has a set of functions that enable you to convert between different calendar systems. The main calendars you will work with are the Gregorian, Julian, and Julian Day Count.

Most Western countries currently use the Gregorian calendar. The Gregorian date October 15, 1582, is equivalent to October 5, 1582, in the Julian calendar. Prior to that date, the Julian calendar was commonly used. Different countries converted to the Gregorian calendar at different times and some not until early in the twentieth century.

Although you may have heard of these two calendars, you might not have heard of the Julian Day Count (JD). It is similar in many ways to a Unix timestamp. It is a count of the number of days since a date around 4000 BC. In itself, it is not particularly useful, but it is useful for converting between formats. To convert from one format to another, you first convert to a Julian Day Count and then to the desired output calendar.

To use these functions under Unix, you first need to compile the calendar extension into PHP with --enable-calendar. These functions are built into the standard Windows install.

To give you a taste for these functions, consider the prototypes for the functions you would use to convert from the Gregorian calendar to the Julian calendar:

int gregoriantojd (int month, int day, int year)
string jdtojulian(int julianday)

To convert a date, you would need to call both of these functions:

$jd = gregoriantojd (9, 18, 1582);
echo jdtojulian($jd);

This call echoes the Julian date in a MM/DD/YYYY format.

Variations of these functions exist for converting between the Gregorian, Julian, French, and Jewish calendars and Unix timestamps.

Further Reading

If you would like to read more about date and time functions in PHP and MySQL, you can consult the relevant sections of the manuals at http://php.net/manual/en/ref.datetime.php and http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html.

If you are converting between calendars, try the manual page for PHP’s calendar functions: http://php.net/manual/en/ref.calendar.php.

Next

One of the unique and useful things you can do with PHP is create images on the fly. Chapter 22, “Generating Images,” discusses how to use the image library functions to achieve some interesting and useful effects.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset