34

I need to know what time zone is currently my users are in based on their IP or http header.

I got many answer regarding this issue, but i could not understood those answer. Some said use -new Date().getTimezoneOffset()/60 (from here). But what does it mean?

I have a date_default_timezone_set("Asia/Calcutta"); in the root of my (index.php) page. So for this I have to get the timezone dynamically and set it in place of Asia/Calcutta.

7
  • michaelapproved.com/articles/… Commented May 13, 2013 at 15:27
  • @elavarasanlee your link is not working Commented May 13, 2013 at 15:28
  • @Ashutosh : The comment below the answer says "This worked for me! Read the comments under the blog post for a couple updates to the code." That's why I gave the link here. Commented May 13, 2013 at 15:36
  • @elavarasanlee I am reading it Commented May 13, 2013 at 15:38
  • 1
    let us continue this discussion in chat Commented May 13, 2013 at 17:24

7 Answers 7

44

To summarize Matt Johnson's answer in terms of code:

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js">
</script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.4/jstz.min.js">
</script>
<script type="text/javascript">
  $(document).ready(function(){
    var tz = jstz.determine(); // Determines the time zone of the browser client
    var timezone = tz.name(); //For e.g.:"Asia/Kolkata" for the Indian Time.
    $.post("url-to-function-that-handles-time-zone", {tz: timezone}, function(data) {
       //Preocess the timezone in the controller function and get
       //the confirmation value here. On success, refresh the page.
     });
  });
</script>
Sign up to request clarification or add additional context in comments.

5 Comments

$.post("url-to-function-that-handles-time-zone", {tz: timezone}, function(data) { //Preocess the timezone in the controller function and get //the confirmation value here. On success, refresh the page. }); I dont understand this line, can you explain this ?
@Vijaykarthik: The Ajax call will send the dynamically obtained timezone to a controller method (as the developer is using Codeigniter - MVC Framework). In controller method he'll be setting the timezone uisng date_default_timezone_set(timezone) which returns false if timezone is invalid! Using this retrun value he has to decide whether or not to refresh the page!
You can use vanilla javascript Intl.DateTimeFormat().resolvedOptions().timeZone instead of an entire library.
@kjdion84 Yes, but the browser support is limited. If you want to support older browser version, it's better to have polyfills in place.
@FernandoTorres I know this is like 8yrs old code, but it's still working: jsfiddle.net/elavarasanlee/2Le0uvp3/2 Could you pls elaborate what's not working for you?
26

Time zone information of the browser is not part of the HTTP spec, so you can't just get it from a header.

If you have location coordinates (from a mobile device GPS, for example), then you can find the time zone using one of these methods. However, geolocation by IP address is not a great solution because often the IP is that of an ISP or proxy server which may be in another time zone.

There are some strategies you can use to try to detect the time zone, such as using jsTimeZoneDetect library, which is a great starting point, but imperfect enough that you can't just rely on that alone. If you're using moment.js, there's a built in function in moment-timezone called moment.tz.guess() that does the same thing.

UPDATE: In modern browsers, you can get the full time zone ID with Intl.DateTimeFormat().resolvedOptions().timeZone which was not available when this answer was originally written.

The idea of using JavaScript's getTimezoneOffset() function is flawed in that you are not getting a time zone - just a single offset for a particular date. See the TimeZone tag wiki's section titled "TimeZone != Offset".

However you look at it, ultimately you have to decide on one of two approaches:

OR

  • Only send time to the browser in UTC, and use JavaScript on the browser to convert to whatever local time zone the user might have their computer set to.

I discuss this in more detail (from a c# perspective) in this answer.

5 Comments

Nice explanation. I would like to use the second approach. But i am beginner in programming. How can i send time to the browser in UTC, and use JavaScript on the browser to convert to whatever local time ?zone
@Ashutosh - You will find answers to each of those separate questions in existing posts.
I like the first approach because let the user to choose what he is on. Relying on detection is just headache from my point of view cause user can change the time accidently.
Do you have an answer for this stackoverflow.com/questions/42062555/…
The second solution takes most web apps pretty far, but it breaks down when emailing users about events with timestamps. The servers run on UTC, so we don't get that automatic adjustment to the user's time zone. Looks like the solution is to autodetect the timezone value on login and send to the server for storing on the user. Then we can use that timezone to adjust emails we send them. Should probably include an input for controlling that on the account settings, just for good measure.
3

Dependencies:

  1. http://www.maxmind.com/download/geoip/api/php/php-latest.tar.gz
  2. http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz

    //Get remote IP
    $ip = $_SERVER['REMOTE_ADDR'];
    
    //Open GeoIP database and query our IP
    $gi = geoip_open("GeoLiteCity.dat", GEOIP_STANDARD);
    $record = geoip_record_by_addr($gi, $ip);
    
    //If we for some reason didnt find data about the IP, default to a preset location.
    if(!isset($record)) {
        $record = new geoiprecord();
        $record->latitude = 59.2;
        $record->longitude = 17.8167;
        $record->country_code = 'SE';
        $record->region = 26;
    }
    
    //Calculate the timezone and local time
    try {
        //Create timezone
        $user_timezone = new DateTimeZone(get_time_zone($record->country_code, ($record->region!='') ? $record->region : 0));
    
        //Create local time
        $user_localtime = new DateTime("now", $user_timezone);
        $user_timezone_offset = $user_localtime->getOffset();        
    }
    //Timezone and/or local time detection failed
    catch(Exception $e) {
        $user_timezone_offset = 7200;
        $user_localtime = new DateTime("now");
    }
    
    echo 'User local time: ' . $user_localtime->format('H:i:s') . '<br/>';
    echo 'Timezone GMT offset: ' . $user_timezone_offset . '<br/>';
    

citation: SGet visitor local time, sunrise and sunset time by IP with MaxMind GeoIP and PHP by Stanislav Khromov

1 Comment

I think the best algorithm would be to select time zone according to geo-ip location combined with user agent time offset. Use geo-ip location to pick up a list of possible timezones (ordered by geo-ip distance between detected location and timezone "home" location) and select the first match that is close to user agent time offset.
1

One solution is to ask them! Especially on members systems where you can capture/register a user - give them a choice at that point. Simple but accurate.

Comments

0

This works fine...

  echo <<<EOE
   <script type="text/javascript">
     if (navigator.cookieEnabled)
       document.cookie = "tzo="+ (- new Date().getTimezoneOffset());
   </script>
EOE;
  if (!isset($_COOKIE['tzo'])) {
    echo <<<EOE
      <script type="text/javascript">
        if (navigator.cookieEnabled) document.reload();
        else alert("Cookies must be enabled!");
      </script>
EOE;
    die();
  }
  $ts = new DateTime('now', new DateTimeZone('GMT'));
  $ts->add(DateInterval::createFromDateString($_COOKIE['tzo'].' minutes'));

Comments

0

Timezone is not available in the HTTP header, but country (abbreviation) is in the ACCEPT_LANGUAGE header. It'll be something like "en-US" (US is the country code). This can be combined with the JavaScript information to get a good idea of the user's timezone.

This is what I'm using in JS:

function timezone() {
  var now = new Date();
  var jano = new Date(now.getFullYear(), 0, 1).getTimezoneOffset()/-60;
  var julo = new Date(now.getFullYear(), 6, 1).getTimezoneOffset()/-60;
  var tz = Math.min(jano, julo);
  if (jano != julo) tz += ((jano < julo) ? 'S' : 'W') + Math.abs(jano - julo);
  return tz;
}

This returns a string like "-6S1" for the central zone (standard time offset of -6 hours, DST active in the summer and adds 1 hour). I use a cookie to make this available to PHP. PHP searches the TZ database for zones that match this, and the country. For here (US, -6S1) there are 7 matching zones, the first is "America/Chicago".

BTW, there are 2 zones in the database where DST adds something other than 1 hour: Lord Howe Island (10.5W0.5) and Troll Station, Antarctica (0W2).

Comments

0

A more modern answer to this question is to put a javascript function on your landing page that sends the information to your PHP backend. I've put in some debugging and verbose options for beginners to use.

<script>
// Function to send the timezone to the server
function setTimezoneOnPageLoad() {
    const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; // Get the user's timezone

    // Make the AJAX request
    fetch('/set-timezone', {
        method: 'POST', // Use POST for sending data
        headers: {
            'Content-Type': 'application/json', // Inform the server we're sending JSON
        },
        body: JSON.stringify({ timezone: timezone }), // Send the timezone as JSON
    })
        .then(response => {
            if (!response.ok) {
                throw new Error(`HTTP error! Status: ${response.status}`);
            }
            return response.json(); // Parse JSON response
        })
        .then(data => {
            // Check the success flag in the JSON response
            if (data.success) {
                console.log(`Success: ${data.message}`);
            } else {
                console.error(`Error: ${data.error}`);
            }
        })
        .catch(error => {
            // Catch and log any errors
            console.error('AJAX request failed:', error);
        });
}

// Fire the function when the page is fully loaded
document.addEventListener('DOMContentLoaded', setTimezoneOnPageLoad);
</script>

Then on the php receiving this call (in this example /set-timezone is the route to your php code):

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    header('Content-Type: application/json'); // Set the correct response type
    $data = json_decode(file_get_contents('php://input'), true);
    session_start();
    $_SESSION['timezone']='';
    if (!empty($data['timezone'])) {
        $timezone = htmlspecialchars($data['timezone'], ENT_QUOTES, 'UTF-8');

        // Validate and set the timezone
        if (in_array($timezone, timezone_identifiers_list())) {
            date_default_timezone_set($timezone);

            // Send a structured response
            echo json_encode([
                'success' => true,
                'message' => "Timezone set successfully.",
                'timezone' => $timezone,
            ]);
            $_SESSION['timezone']=$timezone
        } else {
            echo json_encode([
                'success' => false,
                'error' => "Invalid timezone.",
            ]);
        }
    } else {
        echo json_encode([
            'success' => false,
            'error' => "Timezone not provided.",
        ]);
        
    }
    exit;
}

Now your backend can keep track of this user's session timezone in $_SESSION['timezone']. You can see where this is supported here https://caniuse.com/?search=Intl.DateTimeFormat().resolvedOptions().timeZone for about 96% of all global browsers.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.