Use PHP and JavaScript to Display Local Time

How to display visitors' localtime using JavaScript and PHP without even asking them to select their timezone.

The decision

This can be done with the help of a little piece of JavaScript and the use of a server-side language like PHP, ASP, JSP or any other available to you.

In the example I will show I have used PHP with it's built-in session support (available since PHP 4.0).

Q: But why use JavaScript at all when PHP has it's own localtime() function?

A: PHP's localtime() function will give you the server local time not the user's and that's not what we want.

The concept

We want to show the visitor his/her local time, so what we need is way to get his time zone offset. We can do that in JavaScript with the help of the Date method getTimezoneOffset and then send it to the server to be saved as a session variable. We send this info by modifying all links in the document that point within our site by appending a query variable, e.g. we add ?offset=-180 if the link has no other query variables set. If it has then we add ;offset=-180.

Note: The additional query parameter is separated from the others with ; not & as the latter one has to be escaped as & in HTML.

When we have this info about the user we don't want him/her to send it over and over again as we have it already saved in our session so we don't send the JavaScript then. When displaying the time we use a function that adds the visitors offset to the time and then prints a string identifying the time zone.

An alternative that is not recommended though is to send the browser JavaScript code that uses document.write() to print the date.

Example code

JavaScript code

<?php
session_start();

if ( !isset($_SESSION['offset']) ) {
?>
  <script type="text/javascript">
  window.onload = setLinks

  function setLinks() {
    now = new Date()
    offset = now.getTimezoneOffset();

    for ( i = 0; i < document.links.length; i++ ) {
      with ( document.links[i] ) {
        if ( href.indexOf('http://martin.f2o.org') == 0 ) {
          if ( href.indexOf('?') == -1 ) {
            href += '?offset=' + offset;
          } else {
            href += ';offset=' + offset;
          }
        }
      }
    }
  }
  </script>

<?php
}
?>

We start by opening a PHP code block, and check if our session variable identifying that the user's time zone has been saved is not set. If it isn't then we should send the JavaScript code to the browser to process the links in the document.

Note: Opera 5 and 6 for Linux and Windows has a bug that causes it to strip out trailing slashes from URI's that may cause problems sometimes.

Now for that JavaScript: we first set a handler via window.onload = setLinks. This will execute the setLinks function upon loading of the document, i.e. all external images/CSS/JavaScript has been downloaded and the page is displayed.

The setLinks function will then create a new Date() to get the visitor's time zone, and will loop through all links in the document modifying them as mentioned earlier.

The server code (PHP in our case)

if ( !isset($_SESSION['GMT_offset']) ) {
  $_SESSION['GMT_offset'] = 0;
  $_SESSION['GMT_offset_str'] = '+0:00';
}

This code just sets default values for the GMT offset it none are stored in the session.

Note: In the whole example the new PHP 4.1 style session array is used. If you want to run that code in a previous version of PHP just change $_SESSION to $HTTP_SESSION_VARS, the former is also globally available and the latter has to be imported from the global namespace within functions with a declaration like:

global $HTTP_SESSION_VARS

track_vars must be on, use: php_flag track_vars true in a .htaccess file to achieve this, or set it directly in php.ini.

if ( isset($_GET['offset']) ) {
  $_SESSION['offset'] = $_GET['offset'];
  set_timezone($_GET['offset']);
}

This piece of code checks if the browsers sent a query parameter offset, if so sets the time offset to it by calling the set_timezone function (explanation of the function is given below).

function set_timezone( $offset ) {
  if ( $offset ) {
    $offset = -$offset;
    $_SESSION['GMT_offset'] = 60 * $offset;
    $GMT_offset_str = ( $offset > 0 ) ? '+' : '-';
    $GMT_offset_str .= floor($offset / 60) . ':';
    $GMT_offset_str .= (($offset % 60) < 10 ) ?
      '0' . $offset % 60 : $offset % 60;
    $_SESSION['GMT_offset_str'] = $GMT_offset_str;
  }
}

Now that's the function that does the hard work, it checks if there is an offset from GMT, if so negates its value (if you are located in a GMT +3:00 time zone the JavaScript function getTimezoneOffset() returns -180, i.e. the time in minutes that should be added to your local time to turn it into GMT).

Then we store the offset in seconds in a session variable, and process to the more complicated code that just sets the suffix that identifies the time zone.

function format_datetime( $date ) {
  return ( date('d M Y g:ia', $date + $_SESSION['GMT_offset']) .
  ' GMT ' . $_SESSION['GMT_offset_str']);
}

The format_datetime function is used to display local time, its parameter is an Unix timestamp (a 32-bit unsigned integer representing the number of seconds since the Unix Epoch - 1 Jan 1970), it uses date to display a date in GMT but only after adding the offset seconds. It concatenates the result with the appropriate suffix for the user's time zone.

What else can be done

I tried to pass the offset through a hidden image which is actually a PHP script that sets the session variable but I didn't succeed by doing this.

If you think there's a better way to do it don't hesitate to contact me.

Update (23 Oct 2006): As Carl Henderson mentioned using AJAX instead of modifying all links on the page is a better and more robust solution (it will work fine after a form submit for example).

Related Links

Comments

Local Time

Sorry, why not you state clearly that which code needs to place and on where? Don't grab your tutorial much sense. Cause...I'm a newbie :)

You don't say..

Hmmm, it doesn't seem to work for me. I tried putting the example in a gmt.php file, ran it, but when run it shows a blank page?Your tutorial is a little hard to understand.

Reliable?

Is this method actually a reliable method? Couldn't you simply store the offset as a cookie? I'm interesting in this but I believe it would be easier to give the user a dropdown with all timezone offsets.

No output is supposed by the script

Humpy, it isn't supposed to output anything. Just include it from a different page.
Hal, it probably is a good idea to store it as a cookie - I am storing it for registered users in my database.
As for the dropdown menu with all timezones - it probably is a better idea to have a field where people can type in the offset. As far as I know not many people would actually do it, but most know how to follow a link.

Great idea

I can't believe all the grumpy comments. I think this page is exceedingly well-done and a useful tip. Keep it up Martin!
Tom

A bit odd...

I agree, this page is well done, but why the need for PHP in this instance, since Javascript has enough functions to display the user's local time in many different ways already.

Why PHP

Well the most obvious reason is that you can't get your content from a database, etc. and you won't have so many dates to deal with if only using JavaScript.
Anyway it is a good suggestion for static sites that show dates.

Now I know

I didn't try this, but I tried displaying my local time (only my local time) by adding the offset (+13 from f2o), and it didn't work because of other considerations. Suppose Singapore was one day ahead of f2o. One month. One year. Leap year. It's all possible.
My solution was slightly different. I used mktime to obtain the number of seconds since the UNIX epoch (1/1/1970) in server time, added the offset in seconds, then used the value returned by mktime as an argument in date(). This can be adapted for this script as well.

Why server local time?

Why do you use the server local time at all? You can always get the UTC time with PHP and then add the offset, which is usually within the range -12 to +12 hours.

how to display

please bear with me... i am new to php but very interested to learn. how do i go about using this code to display the current date on the page.

Displaying dates

To display dates in the users' localtime:
1 Include the file (localtime.php)
2 Use the format_datetime() function (the parameter is a Unix timestamp)
PS. And read the article.

no explanation on how to implement

I'm sure this is a great solution but this article is so diificult to read the viewer cannot follow how to use it.
sometimes explanations are above the code block sometimes they are below...
the "download" is also not working or is it explained somewhere else ?
please help possibly provide a working example ?

expected $date format

what is the expected format of $date as input to function
maybe that is why nothing is working for me

header prolem

Hi,
I wondered if you can explain how the above file could be used. I am a newbie. I get error message which is not understanding to me.
I tried to include the file above and call the date function but it was not working. This is the error message I got:
Warning: Cannot send session cookie - headers already sent by (output started at c:\inetpub\wwwroot\databases\localtime.inc:20) in c:\inetpub\wwwroot\databases\localtime.inc on line 22
Warning: Cannot send session cache limiter - headers already sent (output started at c:\inetpub\wwwroot\databases\localtime.inc:20) in c:\inetpub\wwwroot\databases\localtime.inc on line 22
00:26
Please give me your assistance.
God Bless You.

sessions

As this script uses sessions (they need to send cookies) you should call session_start() before any output from the page.

Cookies version

Mr. Martin,
Do you have this script in alternate version that stores the result in persistent cookies?

Another function that does the same

I've wrote a function that does the time converting quite well. You just need to add the time zone you want to the function. For example -5 and 8. The following is the function:
function getGmt($timezone){
$time = gmdate("F j, Y, g:i a",time() + (3600 * $timezone));
return $time;
}
I explained it in more detail @ http://members.tripod.co.uk/chuayw2000/blog/generate.php?page=php

The exact opposite

I've done the exact opposite to this - a constantly updating JavaScript clock that is accurate to your server, not to your user's local time. If you wanted that, it's at http://james.cridland.net/code/clock.html
I'm about to work on something that uses PHP and JavaScript to display a schedule (for a radio station, for example) that displays the programme times in local time, hence why I stumbled across this page.

Cookie Solution - An Example Script

I wrote a very similar example based on a Cookie: http://phpcenter.de/phorum/read.php?f=1&i=33573&t=33498 (Scroll to the bottom of the page. It's in German but my script comments are in English of course.)

Just an complete php alternative...

Hi, this is an alternative that could make things easier:
<?php
setlocale (LC_TIME, $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
$mytime= gmstrftime("%b %d %Y %H:%M:%S", mktime ())."<br>";
echo $mytime;
?>

About displaying local time...

And, to replace u'r five page solution(just joking)
<?php
setlocale (LC_TIME, $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
$mytime= strftime("%b %d %Y %H:%M:%S", mktime ())."<br>";
echo $mytime;
?>

DST

The use of
$_SERVER["HTTP_ACCEPT_LANGUAGE"]
in setlocale isn't a good way of dealing with DST. en-us is what shows on my php_info() page for that variable. That doesn't tell me where my time zone is in the US.

Localtime question

Hi Martin,
It seems to work for me but not sure the result is right. Here is my MySQL query:
$sql = "SELECT UNIX_TIMESTAMP(loaded_time) FROM dbload_delta";
$result = mysql_query("$sql");
list($loaded_time) = mysql_fetch_row($result);
$last_loaded = date("g:i:s A T M d, Y", $loaded_time);
echo("Last delta load @ $last_loaded.");
Output 1:
Last delta load @ 8:09:57 PM PDT Sep 05, 2003.
Using your format_datetime() func:
$user_localtime = format_datetime($loaded_time);
echo " Localtime: $user_localtime";
Output 2:
Localtime: 5 Sep 2003 8:09pm GMT
Where "Output 1" is PDT/PST TZ (Server Time)and "Output 2" is EST TZ (User Time). I'm in EST TZ. Am I supposed to get 5 Sep 2003 11:09pm GMT instead?

Short and Sweet

echo gmdate("F j, Y, g:i a",time() + (3600 * $timezone));
This did the job for me!

Thanks, Martin

Thanks for writing your function and getting this discussion started. It has been very helpful!

time offset

Hey I have a problem that my forum is hosted on an american server so the time for all the posts is wrong, is there a way for the user to select an offset based on their location?

Remind u that it wont work all the time

this depends that the user has the correct timezone set on their machine and also that javascript is running.
I suggest u all just think really hard about the best method for your scripts b4 trying this script

localtime() function

here is a bit of code for displaying localtime with php:
-------------
<?
// USER LOCAL TIME
function GetTZOffset() {
$Offset = date("O", 0);

$Parity = $Offset < 0 ? -1 : 1;
$Offset = $Parity * $Offset;
$Offset = ($Offset - ($Offset % 100))/100*60 + $Offset % 100;
return $Parity * $Offset;
}
$TZOffset = GetTZOffset();
$t_time = time()-$TZOffset*60; #Counter adjust for localtime()
$t_arr = localtime($t_time);
$localTime = $t_arr[3].'-'.$t_arr[4].'-'.$t_arr[5].' '.$t_arr[2].':'.$t_arr[1].':'.$t_arr[0];
echo '<p>your time: '.$localTime;
?>

oups i'm wrong

oups sorry, i'm wrong :(

Lots of Controversy

There is no wrong way to do this - if you've found a way for it to work for you, post it here, and let someone try it. Don't tell someone their method is wrong simply because it doesn't fulfil the needs of your particular piece of software.