Vancouver Web Consultants

May 1, 2009

Getting Time Zone from Latitude & Longitude

The problem:

I was recently tasked with building an application that relied heavily on accurate time zone conversions. I, like many people I soon found out, thought there were just a handful of timezones and the usual select list would suffice:

The deeper I looked into the problem, the deeper it got: the list above only shows a few time offsets from UTC, but it doesn’t tell me, beyond a shadow of a doubt, exactly what time it is where the user is situated, nor can I rely on that time for calculations in the future. The fact is, there are a LOT of timezones in the world. Hundreds. If you have a linux server, you can see exactly how many there are by opening up /usr/share/zoneinfo/zone.tab , but here is the full list:

So it looked like I was going to have to output hundreds of timezone options in order to have something accurate to pass to PHP’s DateTimeZone class and from there perform my calculations against the server time zone. DateTimeZone is insanely great because it offers so much information, including the offset from GMT (or UTC.. the distinction is negligible for this type of application) and whether or not that time zone is currently in daylight savings.

So, the problem was: do I list all the available time zones in the giant select list and hope the user knows which one they’re in? Some would argue that this drop down list is too long to be usable. This is valid because it’s a very long list, and might be confusing. I personally think the jury is still out on this though, because there are around 190 countries in the World on a given day, yet we still seem to find our own. The difference is that most of us know which country we’re in, but will we necessarily know our actual timezone? Users just might not know which one to choose. For example: Vancouver, BC is in time zone “America/Vancouver” whereas Vancouver, WA, just across the border is in time zone “America/Los_Angeles”. This could be a little confusing.

The solutions:

First I thought I could use something like IP2Location data to pull the time zone for the user’s IP, but this would not be reliable for my particular application where the user was choosing a meeting time that was in the future. Where they are when setting the meeting and where they will be when in the meeting could be different, and to make matters worse, one of us could go into daylight savings between now and then. Strike it from the list.

I decided on the approach of using a combination of the Google Maps API and GeoNames.org web service to get the user’s time zone based on the geographic location they enter into a text field, and the latitude / longitude returned by Google’s geocoding service.

The basic steps:

  1. Check that there’s input text
  2. Send to google
  3. Validate the result
  4. Make call to php script for GeoNames
  5. Validate the result
  6. Format a string with the results that the user can confirm
  7. Display results

The HTML:

1
2
3
<input style="padding: 5px; border: 1px solid #333; font-weight: bold" type="text" name="address" id="address"  size="40" maxsize="100"  /> <a href="#" id="lookup">Look-up</a><br />
<span id="result">&nbsp;</span></p>
<div id="map" style="width: 293px; height: 100px"></div>

The Javascript:

My example uses a little Mootools, so you if you base yours on this you will also have to include Mootools Core.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
var Demo = {
     start: function(){
          Demo.lookup();
     },
 
     lookup: function(){
          $('lookup').addEvent('click', function(e){
               e.stop();
               $('result').set('html','&nbsp;');
               var address = $('address').value;
               if(address==''){
                    alert("Please enter your location in the text field");
                    $('address').focus();
               }else{
                    map = new GMap2($("map"));
                    var geocoder;
                    geocoder = new GClientGeocoder();
                    geocoder.getLocations(address, Demo.addToMap);
               }
          })
 
     },
 
     addToMap: function(response){
          map.setCenter(new GLatLng(47.040182144806664,-30.234375), 1);
          map.clearOverlays();
          if (!response || response.Status.code != 200) {
               reset_map();
          } else {
               var place = response.Placemark[0];
               point = new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
               map.checkResize();
               map.setCenter(point, 6);
               var marker = new GMarker(point);
               map.addOverlay(marker);
               var coords = place.Point.coordinates;
               var tmp = String(place.Point.coordinates);
               var coords = tmp.split(",");
               var lat = coords[1];
               var lng = coords[0];
               try {
                    //eg paris
                    var city = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName;
               } catch(err) {
                    try{
                         //eg vancouver
                         var city = place.AddressDetails.Country.AdministrativeArea.Locality.LocalityName;
                    }catch(err){
                         try{
                              //eg dubai
                              var city = place.AddressDetails.Country.Locality.LocalityName;
                         }catch(err){
                              //eg Monaco
                              var city = place.AddressDetails.Country.CountryName;
                         }
                    }
               }
 
               Demo.getTimezone(city,lat,lng);
          }
     },
 
     getTimezone: function(city,lat,lng){
          new Request({
               url: "index.php",
               data: "lat="+lat+"&lng="+lng,
               onSuccess: function(response){
                    var responseArray = JSON.decode(response);
                    var timezone = responseArray.timezone;
                    var result = "You are located in "+city+". <br />Your timezone is "+timezone;
                    $('result').set('html',result);
               }
          }).send();     
     }
}
 
window.addEvent('load', function(){
     Demo.start();
});

The PHP (index.php):

1
2
3
4
5
6
7
8
9
10
if(isset($_POST['lat'])){
     $doc = new DOMDocument();
     $location = "http://ws.geonames.org/timezone?lat=".$_POST['lat'].'&lng='.$_POST['lng'];
     if($doc->load($location)){
          $timezones = $doc->getElementsByTagName("timezoneId");
          $coordinates['timezone'] = $timezones->item(0)->nodeValue;
     }
     echo json_encode($coordinates);
     die;
}

…and that’s it! Now you have a real time zone for the user so you can use PHP’s DateTimeZone class to make reliable date and time calculations. This particular implementation isn’t fool proof.. you would have to have more checks and communication back to the user to make this more functional, but the concept is clear and it sure beats offering a select list of over 400 time zone options.

See a Demo

8 Comments »

  1. I type in my city, state and country – dallas, tx, us and nothing comes back.

    Comment by EllisGL — May 7, 2009 @ 4:05 pm

  2. Yes, today I ran into some trouble with the Google Maps API not responding consistently to the geocoding done with PHP, so I switched the code around a little to do the geocoding with Javascript.

    Comment by Nelson — May 7, 2009 @ 10:30 pm

  3. [...] the Vancouver Web Consultants blog there’s this new tutorial about grabbing latitude and longitude information for a location and determining its current time [...]

    Pingback by Vancouver Web Consultants Blog: Getting Time Zone from Latitude & Longitude | Cole Design Studios — May 8, 2009 @ 10:24 am

  4. [...] Getting time zone from latitude & longitude Plut

    Pingback by Revue de presse | Simple Entrepreneur — May 13, 2009 @ 10:21 pm

  5. nice post, thanks! I just used curl to request the timezone due to better performance.

    Comment by michael — June 15, 2009 @ 9:31 am

  6. Great Article. I was wrestling with having the user select their timezone as well and this seems much better!

    Comment by Charles Himmer — October 8, 2009 @ 10:58 am

  7. @michael
    Michael: where do you request the timezone with Curl?

    Comment by Soloren2001 — November 20, 2009 @ 4:38 pm

  8. Thanks, this worked awesome.

    Comment by Amdizzle — February 23, 2010 @ 6:48 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress