Recipe 3.11. Calculating Time with Time Zones


3.11.1. Problem

You need to calculate times in different time zones. For example, you want to give users information adjusted to their local time, not the local time of your server.

3.11.2. Solution

For simple calculations, you can explicitly add or subtract the offsets between two time zones, as in Example 3-27.

Simple time zone calculation

<?php // If local time is EST $time_parts = localtime(); // California (PST) is three hours earlier $california_time_parts = localtime(time() - 3 * 3600); ?>

In PHP 5.1.0 and later, use date_default_timezone_set( ) to adjust the time zone that PHP uses. Example 3-28 prints the current time twice'once as appropriate for New York and once for Paris.

Changing time zone with date_default_timezone_set( )

<?php $now = time(); date_default_timezone_set('America/New York'); print date('c', $now); date_default_timezone_set('Europe/Paris'); print date('c', $now); ?>

On Unix-based systems with earlier versions of PHP, if you don't know the offsets between time zones, just set the TZ environment variable to your target time zone, as in Example 3-29.

Changing time zone with an environment variable

<?php putenv('TZ=PST8PDT'); $california_time_parts = localtime(); ?>

3.11.3. Discussion

Before we sink too deeply into the ins and outs of time zones, we want to pass along the disclaimer that the U.S. Naval Observatory offers at http://tycho.usno.navy.mil/tzones.html. Namely, official worldwide time zone information is somewhat fragile "because nations are sovereign powers that can and do change their timekeeping systems as they see fit." So, remembering that we are at the mercy of the vagaries of international relations, here are some ways to cope with Earth's many time zones.

The time and date functions were overhauled in PHP 5.1.0, and one of the best parts of that overhaul was greatly improved time zone handling. The added date_default_timezone_get( ) and date_default_timezone_set( ) functions make it a breeze to twiddle time zones to get appropriately formatted output. There is also a new configuration directive, date.timezone, that sets the default time zone to use if you don't call date_default_timezone_set( ).

With these functions available, all you have to do before generating a formatted time or date string with date( ) or strftime( ) is make sure that the currently set default time zone (either from date.timezone or date_default_timezone_set( )) is the one you want to use. If you're building an app that is used by people in multiple time zones, a handy technique is to make the default time zone GMT and then explicitly set the appropriate time zone (based, perhaps, on user preference) before creating a date or time string. This makes it clear in your code that you're generating a time zonespecific value.

The time zones that PHP understands are listed in Appendix H of the PHP Manual (http://www.php.net/timezones). The names of these time zones'such as America/New_York, Europe/Paris, and Africa/Dar_es_Salaam'mirror the structure of the popular zoneinfo database.

If you're using an earlier version of PHP, you have to do the time zone math yourself. For a relatively simple treatment of offsets between time zones, use an array in your program that has the various time zone offsets from UTC. Once you determine what time zone your user is in, just add that offset to the appropriate UTC time and the functions that print out UTC time (e.g., gmdate( ), gmstrftime( )) can print out the correct adjusted time. Example 3-30 adjusts the time from UTC to PST.

Adjusting time from UTC to another time zone

<?php // Find the current time $now = time(); // California is 8 hours behind UTC $now += $pc_timezones['PST']; // Use gmdate() or gmstrftime() to print California-appropriate time print gmstrftime('%c',$now); ?>

Example 3-30 uses the $pc_timezones array defined in Example 3-31, which contains offsets from UTC.

Offsets from UTC

// From Perl's Time::Timezone $pc_timezones = array(   'GMT'  =>   0,           // Greenwich Mean   'UTC'  =>   0,           // Universal (Coordinated)   'WET'  =>   0,           // Western European   'WAT'  =>  -1*3600,      // West Africa   'AT'   =>  -2*3600,      // Azores   'NFT'  =>  -3*3600-1800, // Newfoundland   'AST'  =>  -4*3600,      // Atlantic Standard   'EST'  =>  -5*3600,      // Eastern Standard   'CST'  =>  -6*3600,      // Central Standard   'MST'  =>  -7*3600,      // Mountain Standard   'PST'  =>  -8*3600,      // Pacific Standard   'YST'  =>  -9*3600,      // Yukon Standard   'HST'  => -10*3600,      // Hawaii Standard   'CAT'  => -10*3600,      // Central Alaska   'AHST' => -10*3600,      // Alaska-Hawaii Standard   'NT'   => -11*3600,      // Nome   'IDLW' => -12*3600,      // International Date Line West   'CET'  =>  +1*3600,      // Central European   'MET'  =>  +1*3600,      // Middle European   'MEWT' =>  +1*3600,      // Middle European Winter   'SWT'  =>  +1*3600,      // Swedish Winter   'FWT'  =>  +1*3600,      // French Winter   'EET'  =>  +2*3600,      // Eastern Europe, USSR Zone 1   'BT'   =>  +3*3600,      // Baghdad, USSR Zone 2   'IT'   =>  +3*3600+1800, // Iran   'ZP4'  =>  +4*3600,      // USSR Zone 3   'ZP5'  =>  +5*3600,      // USSR Zone 4   'IST'  =>  +5*3600+1800, // Indian Standard   'ZP6'  =>  +6*3600,      // USSR Zone 5   'SST'  =>  +7*3600,      // South Sumatra, USSR Zone 6   'WAST' =>  +7*3600,      // West Australian Standard   'JT'   =>  +7*3600+1800, // Java   'CCT'  =>  +8*3600,      // China Coast, USSR Zone 7   'JST'  =>  +9*3600,      // Japan Standard, USSR Zone 8   'CAST' =>  +9*3600+1800, // Central Australian Standard   'EAST' => +10*3600,      // Eastern Australian Standard   'GST'  => +10*3600,      // Guam Standard, USSR Zone 9   'NZT'  => +12*3600,      // New Zealand   'NZST' => +12*3600,      // New Zealand Standard   'IDLE' => +12*3600       // International Date Line East );

On Unix systems, you can use the zoneinfo library to do the conversions. This makes your code more compact and also transparently handles DST , as discussed in Recipe 3.12.

To take advantage of zoneinfo in PHP, do all your internal date math with epoch timestamps. Generate them from time parts with the pc_mktime( ) function shown in Example 3-32.

pc_mktime( )

<?php function pc_mktime($tz,$hr,$min,$sec,$mon,$day,$yr) {     putenv("TZ=$tz");     $a = mktime($hr,$min,$sec,$mon,$day,$yr);     putenv('TZ=EST5EDT');   // change EST5EDT to your server's time zone!     return $a; } ?>

Calling putenv( ) before mktime( ) fools the system functions mktime( ) uses into thinking they're in a different time zone. After the call to mktime( ), the correct time zone has to be restored. On the East Coast of the United States, that's EST5EDT. Change this to the appropriate value for your computer's location (see Table 3-5). Manipulating environment variables, however, can cause problems in multithreaded environments. If you're using PHP with a multithreaded web server, it is an extremely good idea to upgrade to at least PHP 5.1.0, so you can use date_default_timezone_set( ).

Time parts are turned into epoch timestamps by pc_mktime( ). Its counterpart, which turns epoch timestamps into formatted time strings and time parts, is pc_strftime( ), shown in Example 3-33.

pc_strftime( )

<?php function pc_strftime($tz,$format,$timestamp) {     putenv("TZ=$tz");     $a = strftime($format,$timestamp);     putenv('TZ=EST5EDT');   // change EST5EDT to your server's time zone!     return $a; } ?>

Example 3-33 uses the same system functionfooling pc_mktime( ) does to get the right results from strftime( ).

The great thing about these functions is that you don't have to worry about the offsets from UTC of different time zones, whether DST is in effect, or any other irregularities of time zone differences. You just set the appropriate zone and let your system libraries do the rest.

Note that the value of the $tz variable in both these functions should not be a time zone name but a zoneinfo zone. zoneinfo zones are more specific than time zones because they correspond to particular places. Table 3-5 contains mappings for appropriate zoneinfo zones for some UTC offsets. The last column indicates whether the zone observes DST.

Table 3-5. zoneinfo zones

UTC offset (hours)

UTC offset (seconds)

zoneinfo zone

DST?

-12

-43,200

Etc/GMT+12

No

-11

-39,600

Pacific/Midway

No

-10

-36,000

US/Aleutian

Yes

-10

-36,000

Pacific/Honolulu

No

-9

-32,400

America/Anchorage

Yes

-9

-32,400

Etc/GMT+9

No

-8

-28,800

PST8PDT

Yes

-8

-28,800

America/Dawson_Creek

No

-7

-25,200

MST7MDT

Yes

-7

-25,200

MST

No

-6

-21,600

CST6CDT

Yes

-6

-21,600

Canada/Saskatchewan

No

-5

-18,000

EST5EDT

Yes

-5

-18,000

EST

No

-4

-14,400

America/Halifax

Yes

-4

-14,400

America/Puerto_Rico

No

-3.5

-12,600

America/St_Johns

Yes

-3

-10,800

America/Buenos_Aires

No

0

0

Europe/London

Yes

0

0

GMT

No

1

3,600

CET

Yes

1

3,600

GMT-1

No

2

7,200

EET

No

2

7,200

GMT-2

No

3

10,800

Asia/Baghdad

Yes

3

10,800

GMT-3

No

3.5

12,600

Asia/Tehran

Yes

4

14,400

Asia/Dubai

No

4

14,400

Asia/Baku

Yes

4.5

16,200

Asia/Kabul

No

5

18,000

Asia/Tashkent

No

5.5

19,800

Asia/Calcutta

No

5.75

20,700

Asia/Katmandu

No

6

21,600

Asia/Novosibirsk

Yes

6

21,600

Etc/GMT-6

No

6.5

23,400

Asia/Rangoon

No

7

25,200

Asia/Jakarta

No

8

28,800

Hongkong

No

9

32,400

Japan

No

9.5

34,200

Australia/Darwin

No

10

36,000

Australia/Sydney

Yes

10

36,000

Pacific/Guam

No

12

43,200

Etc/GMT-13

No

12

43,200

Pacific/Auckland

Yes


Countries around the world don't begin and end DST observance on the same days or at the same times. To calculate time appropriately for an international DSTobserving location, pick a zoneinfo zone that matches your desired location as specifically as possible.

3.11.4. See Also

Recipe 3.12 for dealing with DST; documentation on date_default_timezone_set( ) at http://www.php.net/date_default_timezone_set, on date_default_timezone_get( ) at http://www.php.net/date_default_timezone_get, on putenv( ) at http://www.php.net/putenv, on localtime( ) at http://www.php.net/localtime, on gmdate( ) at http://www.php.net/gmdate, and on gmstrftime( ) at http://www.php.net/gmstrftime; the time zones that PHP knows about are listed at http://www.php.net/timezones; zoneinfo zone names and longitude and latitude coordinates for hundreds of places around the world are available at ftp://elsie.nci.nih.gov/pub/'look for the most recent file whose name begins with tzdata; many links to historical and technical information about time zones, as well as information on the zoneinfo database, can be found at the following address: http://www.twinsun.com/tz/tz-link.htm.




PHP Cookbook, 2nd Edition
PHP Cookbook: Solutions and Examples for PHP Programmers
ISBN: 0596101015
EAN: 2147483647
Year: 2006
Pages: 445

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net