There are several PHP library functions that work with dates and times. Most either generate a Unix timestamp or format a Unix timestamp in a human-readable form.
Date and time is generally represented as a Unix timestamp: the number of seconds since 1 January 1970 00:00:00 Greenwich Mean Time. Most systems represent a timestamp using a signed 32-bit integer, allowing a range of dates from December 13, 1901 through January 19, 2038. While timestamps are convenient to work with in scripts, care must be taken when manipulating timestamps to avoid integer overflow errors. A common source of errors is to compare two timestamps in which the date range is greater than the largest positive integer—a range just over 68 years for a signed 32-bit integer.
WARNING: PHP gives unexpected results when comparing two integers that differ by an amount greater than the largest positive integer, typically 231-1. A safer way to compare large integers is to cast them to floating-point numbers. The following example illustrates this point:$var1 = -2106036000; // 16/08/1902 $var2 = 502808400; // 24/08/1984 // $result is assigned false $result = $var1 < $var2; // $result is assigned true as expected $result = (float) $var1 < (float) $var2;Even floating-point numbers can overflow. To manipulate numbers of arbitrary precision, the BCMath library should be considered.
PHP provides several functions that generate a Unix timestamp. The simplest:
integer time( )
returns the timestamp for the current date and time, as shown in this fragment:
// prints the current timestamp: e.g., 1008553254 echo time( );
To create a timestamp for a past or future date in the range December 13, 1901 through January 19, 2038, the mktime( ) and gmmktime( ) functions are defined:
int mktime(int hour, int minute, int second, int month, int day, int year [, int is_dst]) int gmmktime(int hour, int minute, int second, int month, int day, int year [, int is_dst])
Both create a timestamp from the supplied components; the parameters supplied to gmmktime( ) represent a GMT date and time, while the parameters supplied to mktime( ) represent the local time. This example creates a timestamp for 9:30 A.M. on June 18, 1998:
$aDate = mktime(9, 30, 0, 6, 18, 1998);
Both functions are reasonably tolerant of zero values, and both correctly handle values out-of-range, allowing scripts to add a quantum of time without range checking. If the components of a date are outside the range of dates the function is defined for, -1 is returned. The following example shows how 30 days can be added to a date and time:
$paymentPeriod = 30; // Days // generates a timestamp for 26 June 2002 by // adding 30 days to 27 May 2002 $paymentDue = mktime(0, 0, 0, 5, 27 + $paymentPeriod, 2002); // A different approach adds the appropriate number // of seconds to the timestamp for 27 May 2002 $paymentDue = mktime(0, 0, 0, 5, 27, 2002) + ($paymentPeriod * 24 * 3600);
Both functions allow the supplied date to be interpreted as daylight savings time by setting the flag is_dst to 1.
The order of the arguments to these functions is unusual and easily confused. While the mktime( ) and gmmktime( ) functions are similar to the Unix mktime( ) function, the arguments aren't in the same order.
This function generates a timestamp by parsing the human-readable date and time—between December 13, 1901 and January 19, 2038—from the string time:
integer strtotime(string time)
The function interprets several standard representations of a date, as shown here:
// Absolute dates and times $var = strtotime("25 December 2002"); $var = strtotime("14/5/1955"); $var = strtotime("Fr1, 7 Sep 2001 10:28:07 -1000"); // The current time: equivalent to time( ) $var = strtotime("now"); // Relative times echo strtotime("+1 day"); echo strtotime("-2 weeks"); echo strtotime("+2 hours 2 seconds");
Care should be taken when using strtotime( ) with user-supplied dates. It's better to limit the use of strtotime( ) to cases when the string to be parsed is under the control of the script, for example, checking a minimum age using a relative date:
// date of birth: timestamp for 16 August, 1983 $dob = mktime(0, 0, 0, 16, 8, 1982); // Now check that the individual is over 18 if ((float)$dob < (float)strtotime("-18 years")) echo "Legal to drive in the state of Victoria";
Note that both timestamps are cast to floating-point numbers before comparing them to avoid the integer overflow problem highlighted earlier. A different solution to this problem is presented in Chapter 7.
While a Unix timestamp represents a date and time accurate to the second, many applications require times to be represented to the subsecond. PHP provides the function:
string microtime( )
This returns a string that contains both a Unix timestamp in seconds and a microsecond component. The returned string begins with the microsecond component, followed by the integer timestamp:
// prints the time now in the format "usec sec" // e.g., 0.34783800 1008553410 echo microtime( );
One common use of the function microtime( ) is to generate the seed for a random-number generator:
// Generate a seed. $seed = (float)microtime( ) * 100000000; srand($seed);
Because the microsecond component appears at the start of the string returned from microtime( ), the returned value can be converted to a float with the (float) cast operator. Multiplying the float result by 100,000,000 ensures that you pass a suitably varying integer to the seeding function srand( ). Random-number generation is covered in more detail in Section 2.9.
While the Unix timestamp is programmatically useful, it isn't a convenient display format. The date( ) and gmdate( ) functions return a human-readable formatted date and time:
string date(string format [, integer timestamp]) string gmdate(string format [, integer timestamp])
The format of the returned string is determined by the format argument. A predetermined date can be formatted by passing in the optional timestamp argument. Otherwise, both functions format the current time. The format string uses the formatting characters listed in Table 2-3 to display various components or characteristics of the timestamp. To include the characters from the table, the backslash character is used. The following examples show various combinations:
// Set up a timestamp for 08:15am 24 Aug 1964 $var = mktime(8, 15, 25, 8, 24, 1964); // "24/08/1964" echo date('d/m/Y', $var); // "08/24/64" echo date('m/d/y', $var); // "Born on Thursday 24th of August" echo date('\B\o\r\n \o\n l jS \of F", $var);
Formatting character |
Meaning |
---|---|
a, A |
"am" or "pm"; "AM" or "PM" |
S |
Two-character English ordinal suffix: "st", "nd", "rd", "th" |
d, j |
Day of the month: with leading zeros: "01"; without: "1" |
D, l |
Day of the week: as three letters: "Mon"; spelled out: "Monday" |
M, F |
Month: as three letters: "Jan"; spelled out: "January" |
m, n |
Month: with leading zeros: "01"-"12"; without: "1"-"12" |
h, g |
Hour, 12-hour format: with leading zeros: "09"; without: "9" |
H, G |
Hour, 24-hour format: with leading zeros: "01"; without "1" |
i |
Minutes:"00" to "59" |
s |
Seconds: "00" to "59" |
Y, y |
Year: four digits "2002"; two digits "02" |
r |
RFC-2822 formatted date: e.g., "Tue, 29 Jan 2002 09:15:33 +1000" (added in PHP 4.0.4) |
w |
Day of the week as number: "0" (Sunday) to "6" (Saturday) |
t |
Days in the month: "28" to "31" |
z |
Days in the year: "0" to "365" |
B |
Swatch Internet time |
L |
Leap year: "0" for normal year; "1" for leap-year |
I |
Daylight savings time: "0" for standard time; "1" for daylight savings |
O |
Difference to Greenwich Mean Time in hours: "+0200" |
T |
Time zone setting of this machine |
Z |
Time zone offset in seconds: "-43200" to "43200" |
U |
Seconds since the epoch: 00:00:00 1/1/1970 |
PHP also provides the equivalent functions:
string strftime(string format [, integer timestamp]) string gmstrftime(string format [, integer timestamp])
The format string uses the same formatting character sequences as the C library function strftime( ).
The function checkdate( ) returns true if a given month, day, and year form a valid Gregorian date:
boolean checkdate(integer month, integer day, integer year)
This function isn't based on a timestamp and so can accept a larger range of dates: basically any dates in the years 1 to 32767. It automatically accounts for leap years.
// Works for a wide range of dates $valid = checkdate(1, 1, 1066); // true $valid = checkdate(1, 1, 2929); // true // Correctly identify bad dates $valid = checkdate(13, 1, 1996); // false $valid = checkdate(4, 31, 2001); // false // Correctly handles leap years $valid = checkdate(2, 29, 1996); // true $valid = checkdate(2, 29, 2001); // false
Copyright © 2003 O'Reilly & Associates. All rights reserved.