Skip to content

Instantly share code, notes, and snippets.

@mattbornski
Created March 29, 2012 22:36
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mattbornski/2244444 to your computer and use it in GitHub Desktop.
Save mattbornski/2244444 to your computer and use it in GitHub Desktop.
Determine timezone from lat/long

Goal: To take this: https://graph.facebook.com/105464892820215 And derive this: America/Los Angeles From which we can then derive UTC-0800 or UTC-0700, as appropriate under the daylight madness scheme in effect on the date of interest.

It seems oddly hard to figure out what timezone a given point in space is located in. Looking around, there are only a few APIs which provide this information (http://www.earthtools.org/webservices.htm#timezone and http://www.worldweatheronline.com/time-zone-api.aspx), and only a few datasets which seem to contain it; most of them are in serious GIS formats, and expect you to query them in some manual fashion using a proprietary GIS tool.

I'm not really interested in that; I want a piece of code I can just ask "what timezone is this in" and get an answer, without installing some huge piece of software I don't have a license to or worrying about rate limits from somebody's API. So I'm going to take a shapefile I found here (http://efele.net/maps/tz/world/) and see if we can turn it into something more easily queryable by Javascript, since I'm on a NodeJS kick recently.

Jim Vallandingham (that's quite a name) posted a writeup here (http://vallandingham.me/shapefile_to_geojson.html) about his experience converting to GeoJSON, so I'll try to use his experience as a guide.

nixon:~ matt$ brew install gdal
==> Installing gdal dependency: giflib
==> Downloading http://downloads.sourceforge.net/project/giflib/giflib%204.x/giflib-4.1.6/giflib-4.1.6.tar.bz2
######################################################################## 100.0%
==> ./configure --prefix=/usr/local/Cellar/giflib/4.1.6 --disable-debug
==> make install
/usr/local/Cellar/giflib/4.1.6: 37 files, 712K, built in 18 seconds
==> Installing gdal dependency: proj
==> Downloading http://download.osgeo.org/proj/proj-4.7.0.tar.gz
######################################################################## 100.0%
==> Downloading http://download.osgeo.org/proj/proj-datumgrid-1.5.zip
######################################################################## 100.0%
==> ./configure --prefix=/usr/local/Cellar/proj/4.7.0 --disable-debug
==> make install
/usr/local/Cellar/proj/4.7.0: 49 files, 5.6M, built in 28 seconds
==> Installing gdal dependency: geos
==> Downloading http://download.osgeo.org/geos/geos-3.3.1.tar.bz2
######################################################################## 100.0%
==> ./configure --prefix=/usr/local/Cellar/geos/3.3.1 --disable-debug
==> make install
/usr/local/Cellar/geos/3.3.1: 369 files, 8.4M, built in 2.8 minutes
==> Installing gdal
==> Downloading http://download.osgeo.org/gdal/gdal-1.8.1.tar.gz
######################################################################## 100.0%
==> ./configure --prefix=/usr/local/Cellar/gdal/1.8.1 --disable-debug --with-local=/usr/local/Cellar/gdal/1.8.1 --with-threads --with-libtool --with-libtiff=internal --with-geotiff=internal --with-pcraster=internal --with-pcidsk=internal --with-bsb --with-grib --with-pam --with-libz
==> make
==> make install
==> python setup.py install_lib --install-dir=/usr/local/Cellar/gdal/1.8.1/lib/python
==> Caveats
This version of GDAL was built with Python support.  In addition to providing
modules that makes GDAL functions available to Python scripts, the Python
binding provides ~18 additional command line tools.  However, both the Python
bindings and the additional tools will be unusable unless the following
directory is added to the PYTHONPATH:
    /usr/local/lib/python
==> Summary
/usr/local/Cellar/gdal/1.8.1: 168 files, 28M, built in 5.8 minutes
nixon:~ matt$
nixon:shapefile matt$ cd shapefile/
nixon:shapefile matt$ ls -l 
total 71288
-rwxr-xr-x@ 1 matt  staff     12004 Mar 29 15:33 index.html
-rwxr-xr-x@ 1 matt  staff    859758 Mar 29 15:33 tz_world.dbf
-rwxr-xr-x@ 1 matt  staff    136708 Mar 29 15:33 tz_world.png
-rwxr-xr-x@ 1 matt  staff       257 Mar 29 15:33 tz_world.prj
-rwxr-xr-x@ 1 matt  staff  35257332 Mar 29 15:33 tz_world.shp
-rwxr-xr-x@ 1 matt  staff    221956 Mar 29 15:33 tz_world.shx
nixon:shapefile matt$ /usr/local/Cellar/gdal/1.8.1/bin/ogr2ogr -f geoJSON tz_world.json tz_world.shp 
nixon:shapefile matt$ ls -l
total 188544
-rwxr-xr-x@ 1 matt  staff     12004 Mar 29 15:33 index.html
-rwxr-xr-x@ 1 matt  staff    859758 Mar 29 15:33 tz_world.dbf
-rw-r--r--  1 matt  staff  60032096 Mar 29 15:34 tz_world.json
-rwxr-xr-x@ 1 matt  staff    136708 Mar 29 15:33 tz_world.png
-rwxr-xr-x@ 1 matt  staff       257 Mar 29 15:33 tz_world.prj
-rwxr-xr-x@ 1 matt  staff  35257332 Mar 29 15:33 tz_world.shp
-rwxr-xr-x@ 1 matt  staff    221956 Mar 29 15:33 tz_world.shx
nixon:shapefile matt$ 

At this point I discovered that people had made Javascript libraries and tools to do this exact task. Good for them. Feel free to use one (like this: https://github.com/wavded/js-shapefile-to-geojson) if you want to do this process yourself. I'm only interested in one file, so this will be good enough for me.

At this point, we have a GeoJSON file which has a bunch of polygons for various timezones. After looking around for a tool which could use this, I found lots of tools which would map it for me (nice for some people, but not what I needed). I gave up, and decided that since it's just JSON, I could parse it myself. So I wrote this:

http://github.com/mattbornski/tzwhere

http://search.npmjs.org/#/tzwhere

It can tell you things about the timezone at (hopefully) any location on earth. Test cases only cover one, though, so if you find a hole, let me know. I used data from the source listed above, plus a few modules other people had written to interrogate geographic polygons and to manipulate dates in different timezones. In my opinion, the most function is the "dateAt" function, which (if I did things right) lets you get the Javascript Date object for a semantic time at a particular geographic location. So if you want to wish your friends in the White House a happy new year (automatically), try this:

var TwilioClient = require('twilio').Client;
var tzwhere = require('tzwhere');

setTimeout(function () {
  var client = new TwilioClient(<sid>, <token≥, <hostname>);
  var phone = client.getPhoneNumber(<phoneNumber>);
  phone.setup(function () {
    phone.sendSms('+12024561414','Happy new year!', null, function () {
      return process.exit();
    });
  // Note that Javascript months are zero-indexed
}, tzwhere.dateAt(38.897663, -77.036562, 2013, 0, 1, 0, 0, 0, 0) - Date.now());

Probably best not to run that one until a little after Christmas, though...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment