Juggling time zones
Handling times for different timezones is one of the usual things I had to face with every project that has in one way or the other involves the element of time.
The usual projects I work on store dates into a datetime field in the database. This means that the date must use the YYYY-MM-DD HH:MM:SS format (e.g. 2009-09-03 07:45:00).
One of the first things you’d want to do is to let the user specify a timezone setting for that user account (assuming this is in a multi-user environment, as most web applications are). You could view all the timezones using this code:
foreach(DateTimeZone::listAbbreviations() AS $timezone_abbreviation=>$timezones){
foreach($timezones AS $timezone)
if(isset($timezone['timezone_id']))
echo '<li>'.$timezone_abbreviation.' - ' . $timezone['timezone_id'] . '
<ul>
<li>Uses DST: ' . ($timezone['dst']===TRUE?'Yes':'No') . '</li>
<li>Offset: ' . $timezone['offset'] . '</li>
</ul></li>';
}
echo '</ul>';
You could modify the code above to create a drop-down list of the different timezones to make it easier for the user to pick a timezone (because simply writing GMT+8 or UTC+8 might be confusing for some people).
Next, we will have to convert all of our stored dates into a single timezone, for simplicity, I use GMT/UTC as a reference timezone (since it is easy to add timezone offsets to it). If you store your dates in a datetime field, you can perform the following conversion after retrieving the timestamp from the database:
// and $offset is the timezone offset we got based on the user's settings
$parsedtime = '2009-09-15 12:00:00';
$offset = 8*60*60; // this is GMT +8
// get the GMT counterpart of the parsedtime
$unix_time = strtotime($parsedtime . ' GMT');
echo gmdate('m d Y h:iA',$unix_time-$offset); // displays: 09 15 2009 04:00AM
So that means, 12nn of September 15, 2009 is 4am of September 15, 2009 in GMT/UTC.
Let’s say we had a Calendar application, and you wanted to set an alarm for 6pm on that same day. You could do the something like the this (assuming you wrote some sort of class for this thing):
echo $reminder->timeLeft();
Since the current date and time was 12nn of September 15, 2009, this means that the above reminder will display “6 hours left”, depending on how the timeLeft() method is formatted.
If we didn’t convert the date into a standard timezone, this will force our functions to use the server’s timezone setting and that might not be what you want.
i observed that you have 3 equal signs in this snippet
($timezone['dst']===TRUE?’Yes’:'No’)
is this php-ish for ternary op?
btw! i really like the colored code effect bro… nice!
yep, that’s ternary operation
the equal signs is a special kind of comparison, which means “must be equal to and must be of the same data type”
because PHP has data type juggling, which means if:
$value = 0;
this means that:
if($value == FALSE) will evaluate as TRUE, since 0 is also equal to FALSE,
but if($value === FALSE) will evaluate to FALSE because 0 is not a boolean value
nifty! in the former if() statement, would it mean that FALSE is being promoted to, say, an “int” type as in C? i didn’t see any type declaration for $value so it must mean that php must have some sort of auto variable type assignment ala PERL. would it mean that the first php statement that references $value also binds it to the type being being by the statement and that succeeding references to $value will throw type errors?
say $value = 1 + 1 ; would imply $value is a number. then if ($value == FALSE) will not behave as expected. php is still very very voodoo to me, but i’m slowly up picking interest!
err s/being being/being referenced/
@nil acuna
We call that “type juggling” in PHP, here’s a reference:
http://us3.php.net/manual/en/language.types.type-juggling.php
The variables are treated contextually, e.g. if you add “100″ (a string) to 100 (an integer), you get 200 (integer). But if you concatenate “100″ and 100, you get “100100″ (string).
Type casting can also be done if you’re used to it.
if($value == TRUE)
- is the same as writing if($value)
this means $value must contain any value which is not the equivalent of FALSE, meaning, all the following values will cause that condition to evaluate as true:
$value = 1; // integer
$value = ‘chuck’; // string
$value = TRUE; // boolean
$value = ‘chuck’ . ‘ cerrillo’; // string concatenation
$value = 100 + 1; // integer
while all of the following will evaluate as FALSE:
$value = FALSE; // boolean FALSE
$value = 0; // 0 = FALSE
$value = ‘0′; // ‘0′ => 0 = FALSE
$value = NULL; // since there’s no value to check, it’s FALSE
but if you instead used this:
if($value === TRUE)
only $value = TRUE; will evaluate as TRUE
Here’s a practical example for that… if you are to perform string matching and you wanted to find the offset of the matched string (remember strcmp during highschool days?)
Say, we have this string:
$string = “I would like to buy a hamburger”;
…and you wanted to find… say… “hamburger”. We’ll be using the strpos() function to get the offset: http://us3.php.net/manual/en/function.strpos.php
Note: Returns the position as an integer. If needle is not found, strpos() will return boolean FALSE.
so if you do this:
$string = “I would like to buy a hamburger”;
if( strpos($string,’hamburger’) == FALSE )
echo ‘There is no hamburger…’;
else
echo ‘We found a hamburger!’;
This will display “We found a hamburger!” because the string ‘hamburger’ is found at position 22. But what if we had this string instead?
$string = “hamburger and fries is a good combination”;
Using the same condition, this will display “Theere is no hamburger…”. Even though we can find it at position 0 of $string. Remember type juggling. 0 = FALSE.
so if you do it this way instead
$string = “hamburger and fries is a good combination”;
if( strpos($string,’hamburger’) === FALSE )
echo ‘There is no hamburger…’;
else
echo ‘We found a hamburger!’;
It would only evaluate as FALSE when strpos does not find the string.
oohhhh! clearer! nice nice!
Hello from Russia!
Can I quote a post “No teme” in your blog with the link to you?
sure
I wrote a similar blog on this subject but you nailed it here.