html - specific - php get user timezone




Determine a user's timezone (16)

Is there a standard way for a web server to be able to determine a user's timezone within a web page?

Perhaps from an HTTP header or part of the user-agent string?


A simple way to do it is by using:

new Date().getTimezoneOffset();

Don't use the IP address to definitively determine location (and hence timezone)-- that's because with NAT, proxies (increasingly popular), and VPNs, IP addresses do not necessarily realistically reflect the user's actual location, but the location at which the servers implementing those protocols reside.

Similar to how US area codes are no longer useful for locating a telephone user, given the popularity of number portability.

IP address and other techniques shown above are useful for suggesting a default that the user can adjust/correct.


First, understand that time zone detection in JavaScript is imperfect. You can get the local time zone offset for a particular date and time using getTimezoneOffset on an instance of the Date object, but that's not quite the same as a full IANA time zone like America/Los_Angeles .

There are some options that can work though:

  • Most modern browsers support IANA time zones in their implementation of the ECMAScript Internationalization API , so you can do this:

    const tzid = Intl.DateTimeFormat().resolvedOptions().timeZone;

    The result is a string containing the IANA time zone setting of the computer where the code is running.

    Supported environments are listed in the Intl compatibility table . Expand the DateTimeFormat section, and look at the feature named resolvedOptions().timeZone defaults to the host environment .

    • Some libraries, such as Luxon use this API to determine the time zone through functions like luxon.Settings.defaultZoneName .
  • If you need to support an wider set of environments, such as older web browsers, you can use a library to make an educated guess at the time zone. They work by first trying the Intl API if it's available, and when it's not available, they interrogate the getTimezoneOffset function of the Date object, for several different points in time, using the results to choose an appropriate time zone from an internal data set.

    Both https://bitbucket.org/pellepim/jstimezonedetect and moment-timezone have this functionality.

    // using jsTimeZoneDetect
    var tzid = jstz.determine().name();
    
    // using moment-timezone
    var tzid = moment.tz.guess();

    In both cases, the result can only be thought of as a guess. The guess may be correct in many cases, but not all of them.

    Additionally, these libraries have to be periodically updated to counteract the fact that many older JavaScript implementations are only aware of the current daylight saving time rule for their local time zone. More details on that here.

Ultimately, a better approach is to actually ask your user for their time zone. Provide a setting that they can change. You can use one of the above options to choose a default setting, but don't make it impossible to deviate from that in your app.

There's also the entirely different approach of not relying on the time zone setting of the user's computer at all. Instead, if you can gather latitude and longitude coordinates, you can resolve those to a time zone using one of these methods . This works well on mobile devices.


Getting a valid TZ Database timezone name in PHP is a two-step process:

  1. With JavaScript, get timezone offset in minutes through getTimezoneOffset . This offset will be positive if the local timezone is behind UTC and negative if it is ahead. So you must add an opposite sign to the offset.

    var timezone_offset_minutes = new Date().getTimezoneOffset();
    timezone_offset_minutes = timezone_offset_minutes == 0 ? 0 : -timezone_offset_minutes;

    Pass this offset to PHP.

  2. In PHP convert this offset into a valid timezone name with timezone_name_from_abbr function.

    // Just an example.
    $timezone_offset_minutes = -360;  // $_GET['timezone_offset_minutes']
    
    // Convert minutes to seconds
    $timezone_name = timezone_name_from_abbr("", $timezone_offset_minutes*60, false);
    
    // America/Chicago
    echo $timezone_name;</code></pre>

I've written a blog post on it: How to Detect User Timezone in PHP . It also contains a demo.



Here is an article (with source code) that explains how to determine and use localized time in an ASP.NET (VB.NET, C#) application:

It's About Time

In short, the described approach relies on the JavaScript getTimezoneOffset function, which returns the value that is saved in the session cookie and used by code-behind to adjust time values between GMT and local time. The nice thing is that the user does not need to specify the time zone (the code does it automatically). There is more involved (this is why I link to the article), but provided code makes it really easy to use. I suspect that you can convert the logic to PHP and other languages (as long as you understand ASP.NET).


I still have not seen a detailed answer here that gets the time zone. You shouldn't need to geocode by IP address or use PHP (lol) or incorrectly guess from an offset.

Firstly a time zone is not just an offset from GMT. It is an area of land in which the time rules are set by local standards. Some countries have daylight savings, and will switch on DST at differing times. It's usually important to get the actual zone, not just the current offset.

If you intend to store this timezone, for instance in user preferences you want the zone and not just the offset. For realtime conversions it won't matter much.

Now, to get the time zone with javascript you can use this:

>> new Date().toTimeString();
"15:46:04 GMT+1200 (New Zealand Standard Time)"
//Use some regular expression to extract the time.

However I found it easier to simply use this robust plugin which returns the Olsen formatted timezone:

https://github.com/scottwater/jquery.detect_timezone


If you happen to be using OpenID for authentication, Simple Registration Extension would solve the problem for authenticated users (You'll need to convert from tz to numeric).

Another option would be to infer the time zone from the user agent's country preference. This is a somewhat crude method (won't work for en-US), but makes a good approximation.


JavaScript is the easiest way to get the client's local time. I would suggest using an XMLHttpRequest to send back the local time, and if that fails, fall back to the timezone detected based on their IP address.

As far as geolocation, I've used MaxMind GeoIP on several projects and it works well, though I'm not sure if they provide timezone data. It's a service you pay for and they provide monthly updates to your database. They provide wrappers in several web languages.


JavaScript:

function maketimus(timestampz)
{
    var linktime = new Date(timestampz * 1000);
    var linkday = linktime.getDate();
    var freakingmonths = new Array();

    freakingmonths[0]  = "jan";
    freakingmonths[1]  = "feb";
    freakingmonths[2]  = "mar";
    freakingmonths[3]  = "apr";
    freakingmonths[4]  = "may";
    freakingmonths[5]  = "jun";
    freakingmonths[6]  = "jul";
    freakingmonths[7]  = "aug";
    freakingmonths[8]  = "sep";
    freakingmonths[9]  = "oct";
    freakingmonths[10] = "nov";
    freakingmonths[11] = "dec";

    var linkmonthnum = linktime.getMonth();
    var linkmonth = freakingmonths[linkmonthnum];
    var linkyear = linktime.getFullYear();
    var linkhour = linktime.getHours();
    var linkminute = linktime.getMinutes();

    if (linkminute < 10)
    {
        linkminute = "0" + linkminute;
    }

    var fomratedtime = linkday + linkmonth + linkyear + " " +
                       linkhour + ":" + linkminute + "h";
    return fomratedtime;
}

Simply provide your times in Unix timestamp format to this function; JavaScript already knows the timezone of the user.

Like this:

PHP:

echo '<script type="text/javascript">
var eltimio = maketimus('.$unix_timestamp_ofshiz.');
document.write(eltimio);
</script><noscript>pls enable javascript</noscript>';

This will always show the times correctly based on the timezone the person has set on his/her computer clock. There is no need to ask anything to anyone and save it into places, thank god!


The magic all seems to be in

visitortime.getTimezoneOffset()

That's cool, I didn't know about that. Does it work in Internet Explorer, etc? From there you should be able to use JavaScript to Ajax, set cookies, whatever. I'd probably go the cookie route myself.

You'll need to allow the user to change it though. We tried to use geolocation (via maxmind) to do this a while ago, and it was wrong reasonably often - enough to make it not worth doing, so we just let the user set it in their profile, and show a notice to users who haven't set theirs yet.


The most popular (==standard?) way of determining the time zone I've seen around is simply asking the users themselves. If your website requires subscription, this could be saved in the users' profile data. For anon users, the dates could be displayed as UTC or GMT or some such.

I'm not trying to be a smart aleck. It's just that sometimes some problems have finer solutions outside of any programming context.



Try this PHP code:

<?php
    $ip = $_SERVER['REMOTE_ADDR'];
    $json = file_get_contents("http://api.easyjquery.com/ips/?ip=" . $ip . "&full=true");
    $json = json_decode($json,true);
    $timezone = $json['LocalTimeZone'];
?>

With the PHP date function you will get the date time of server on which the site is located. The only way to get the user time is to use JavaScript.

But I suggest you to, if your site has registration required then the best way is to ask the user while to have registration as a compulsory field. You can list various time zones in the register page and save that in the database. After this, if the user logs in to the site then you can set the default time zone for that session as per the users’ selected time zone.

You can set any specific time zone using the PHP function date_default_timezone_set . This sets the specified time zone for users.

Basically the users’ time zone is goes to the client side, so we must use JavaScript for this.

Below is the script to get users’ time zone using PHP and JavaScript.

<?php
    #http://www.php.net/manual/en/timezones.php List of Time Zones
    function showclienttime()
    {
        if(!isset($_COOKIE['GMT_bias']))
        {
?>

            <script type="text/javascript">
                var Cookies = {};
                Cookies.create = function (name, value, days) {
                    if (days) {
                        var date = new Date();
                        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
                        var expires = "; expires=" + date.toGMTString();
                    }
                    else {
                        var expires = "";
                    }
                    document.cookie = name + "=" + value + expires + "; path=/";
                    this[name] = value;
                }

                var now = new Date();
                Cookies.create("GMT_bias",now.getTimezoneOffset(),1);
                window.location = "<?php echo $_SERVER['PHP_SELF'];?>";
            </script>

            <?php

        }
        else {
          $fct_clientbias = $_COOKIE['GMT_bias'];
        }

        $fct_servertimedata = gettimeofday();
        $fct_servertime = $fct_servertimedata['sec'];
        $fct_serverbias = $fct_servertimedata['minuteswest'];
        $fct_totalbias = $fct_serverbias  $fct_clientbias;
        $fct_totalbias = $fct_totalbias * 60;
        $fct_clienttimestamp = $fct_servertime + $fct_totalbias;
        $fct_time = time();
        $fct_year = strftime("%Y", $fct_clienttimestamp);
        $fct_month = strftime("%B", $fct_clienttimestamp);
        $fct_day = strftime("%d", $fct_clienttimestamp);
        $fct_hour = strftime("%I", $fct_clienttimestamp);
        $fct_minute = strftime("%M", $fct_clienttimestamp);
        $fct_second = strftime("%S", $fct_clienttimestamp);
        $fct_am_pm = strftime("%p", $fct_clienttimestamp);
        echo $fct_day.", ".$fct_month." ".$fct_year." ( ".$fct_hour.":".$fct_minute.":".$fct_second." ".$fct_am_pm." )";
    }

    showclienttime();
?>

But as per my point of view, it’s better to ask to the users if registration is mandatory in your project.


You could do it on the client with moment-timezone and send the value to server; sample usage:

> moment.tz.guess()
"America/Asuncion"




timezone-offset