90

When users register with our app, we are able to infer their zip code when we validate them against a national database. What would be the best way to determine a good potential guess of their time zone from this zip code?

We are trying to minimize the amount of data we explicitly have to ask them for. They will be able to manually set the time zone later if our best guess is wrong. I realize zip codes won't help with figuring out the time zone outside the US, but in that case we'd have to manually ask anyway, and we deal predominantly with the US regardless.

I've found a lot of zip code databases, and so far only a few contain time zone information, but those that do are not free, such as this one. If it's absolutely necessary to pay a subscription to a service in order to do this, then it will not be worth it and we will just have to ask users explicitly.

Although language isn't particularly relevant as I can probably convert things however needed, we're using PHP and MySQL.

Doug Kavendek
  • 3,624
  • 4
  • 31
  • 43

12 Answers12

34

I just found a free zip database that includes time offset and participation in DST. I do like Erik J's answer, as it would help me choose the actual time zone as opposed to just the offset (because you never can be completely sure on the rules), but I think I might start with this, and have it try to find the best time zone match based on offset/dst configuration. I think I may try to set up a simple version of Development 4.0's answer to check against what I get from the zip info as a sanity test. It's definitely not as simple as I'd hope, but a combination should get me at least 90% sure of a user's time zone.

Doug Kavendek
  • 3,624
  • 4
  • 31
  • 43
  • @Doug: Anything that relates to GeoCoding will never be 100% correct, all the more so when you're only acting at the ZIP level. Still, if you can be correct 90%+ of the time, it will probably be a benefit to your users. Worst you're likely to be off is one hour. – Eric J. Mar 16 '10 at 18:38
  • 3
    watch out, free zip databases are almost always obsolete, since the postal service changes that file monthly. also see http://semaphorecorp.com/cgi/zip5.html – joe snyder Jun 25 '10 at 17:38
  • That link brings up some good points, but since I'm just using this to make a guess at the general region (and allowing for corrections), I shouldn't have to worry too much. Unless a zip code can straddle multiple timezones -- but in that case, it's already an edge case, and since we will never ask for user's addresses we wouldn't be able to use those to further validate. But indeed, it probably would be useful for us to actually subscribe to one before things go live, to keep up-to-date. The free one is at least good for testing. – Doug Kavendek Jun 25 '10 at 18:15
  • 3
    @joesnyder Link is broken, could you update or at least explain what was there? – dlsso Mar 28 '19 at 21:59
  • 2
    @dlsso that link is now [Why all 5-digit ZIP Code™ lists are obsolete](http://maf.directory/zp4/zip5.html) and [Old ZIP codes](http://maf.directory/misc/oldzips.html) – joe snyder Mar 31 '19 at 22:48
  • @joesnyder How can we pull the changes from the postal service in real time, or batched monthly or just download the whole current dataset from them programmatically? – Billy left SE for Codidact Oct 02 '20 at 02:47
  • @billy Go to [https://www.usps.com/business/web-tools-apis/](https://www.usps.com/business/web-tools-apis/) – joe snyder Oct 03 '20 at 19:54
  • The ZIP links moved yet again. Go to [https://sites.google.com/site/masteraddressfile/zp4/zip5](https://sites.google.com/site/masteraddressfile/zp4/zip5) and [https://sites.google.com/site/masteraddressfile/misc/oldzips](https://sites.google.com/site/masteraddressfile/misc/oldzips) – joe snyder Oct 03 '20 at 19:57
  • 3
    The link in the post is broken. – Adam C. Oct 21 '21 at 18:00
29

Most states are in exactly one time zone (though there are a few exceptions). Most zip codes do not cross state boundaries (though there are a few exceptions).

You could quickly come up with your own list of time zones per zip by combining those facts.

Here's a list of zip code ranges per state, and a list of states per time zone.

You can see the boundaries of zip codes and compare to the timezone map using this link, or Google Earth, to map zips to time zones for the states that are split by a time zone line.

The majority of non-US countries you are dealing with are probably in exactly one time zone (again, there are exceptions). Depending on your needs, you may want to look at where your top-N non-US visitors come from and just lookup their time zone.

Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • 1
    Wow, what are the exceptions? – Hamish Grubijan Mar 16 '10 at 16:53
  • 6
    @Hamish: Exceptions for states in multiple timezones you can see in the Wikipedia link (states per time zone). My colleague is mapping ZIPs to states as we speak and came across a few ZIPs that cross state lines. One example is 42223. – Eric J. Mar 16 '10 at 16:57
  • From what i know, Montana, ORegon, Idaho, dakotas, nebraska, kansas, texas, and some of the mid eastern states – dassouki Mar 16 '10 at 16:57
  • 2
    Also note that some states (only Arizona & Hawaii I *think*) don't observe daylight savings time. – Jon-Eric Mar 16 '10 at 17:01
  • 1
    States in the Northwest of the US have a million and one zip codes per-state; fair warning. – Qix - MONICA WAS MISTREATED Mar 29 '13 at 21:51
  • @Jon-Eric: There are also some counties in the midwest that don't observe daylight savings, even though the state they are in does. – Eric J. Mar 31 '13 at 01:41
  • 1
    This idea of *most* states only having one time zone, or *most* countries only having one time zone, is like saying "I only want *most* of my customers to be happy". I have had a least twice in my life moved into a "new" zip code that wasn't in certain databases - making things more difficult than you would think. There are a lot more really good reasons not to resolve time zone by zip code. I listed some of them [here](http://stackoverflow.com/a/16348665/634824). – Matt Johnson-Pint May 09 '13 at 04:13
  • @MattJohnson: Yes, new ZIP codes are added frequently enough, and old ZIP codes are redefined (often split). Also, the area defined by a ZIP code need not even be entirely connected. The ZIP I grew up in is broken into a number of chunks, like islands, surrounded by other ZIP codes. They are not great indicators of any boundary other than ZIP boundaries. They cross time zones, city lines, county lines, and in at least one case cross a state line. – Eric J. May 09 '13 at 17:06
  • 2
    It's a lot more than a few exceptions. http://www.timetemperature.com/tzus/indiana_time_zone.shtml – Chris Moschini Aug 18 '14 at 21:22
15

I created an Open-Source (MIT licensed) MySQL database table that cross-references zip codes and timezones and uploaded it to sourceforge.net:

http://sourceforge.net/projects/zip2timezone/files/

It is sourced from four locations (primary Yahoo PlaceFinder API - thanks @Chris N)

See the README file for more information and instructions.

chriv
  • 752
  • 1
  • 7
  • 18
9

If you want, you can also get a feel for the timezone by asking the browser Josh Fraser has a nice write up on it here

var rightNow = new Date();
var jan1 = new Date(rightNow.getFullYear(), 0, 1, 0, 0, 0, 0);
var temp = jan1.toGMTString();
var jan2 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
var std_time_offset = (jan1 - jan2) / (1000 * 60 * 60);

The second thing that you need to know is whether the location observes daylight savings time (DST) or not. Since DST is always observed during the summer, we can compare the time offset between two dates in January, to the time offset between two dates in June. If the offsets are different, then we know that the location observes DST. If the offsets are the same, then we know that the location DOES NOT observe DST.

var june1 = new Date(rightNow.getFullYear(), 6, 1, 0, 0, 0, 0);
temp = june1.toGMTString();
var june2 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
var daylight_time_offset = (june1 - june2) / (1000 * 60 * 60);
var dst;
if (std_time_offset == daylight_time_offset) {
    dst = "0"; // daylight savings time is NOT observed
} else {
    dst = "1"; // daylight savings time is observed
}

All credit for this goes to Josh Fraser.

This might help you with customers outside the US, and it might complement your zip approach.

Here is a SO questions that touch on getting the timezone from javascript

Community
  • 1
  • 1
Development 4.0
  • 2,705
  • 1
  • 22
  • 17
  • 1
    thanks! As Josh mentions on his site, Jon Nylander has "written a a more robust solution. Use his version instead.". His version is here: https://bitbucket.org/pellepim/jstimezonedetect – Brad Parks Jun 20 '12 at 14:49
6

Google has a specific API for this: https://developers.google.com/maps/documentation/timezone/

eg: https://maps.googleapis.com/maps/api/timezone/json?location=40.704822,-74.0137431&timestamp=0

{
  dstOffset: 0,
  rawOffset: -18000,
  status: "OK",
  timeZoneId: "America/New_York",
  timeZoneName: "Eastern Standard Time"
}

They require a unix timestamp on the querystring. From the response returned it appears that timeZoneName takes into account daylight savings, based on the timestamp, while timeZoneId is a DST-independent name for the timezone.

For my use, in Python, I am just passing timestamp=0 and using the timeZoneId value to get a tz_info object from pytz, I can then use that to localize any particular datetime in my own code.

I believe for PHP similarly you can find "America/New_York" in http://pecl.php.net/package/timezonedb

Anentropic
  • 32,188
  • 12
  • 99
  • 147
  • 4
    Note that the licensing for Google's geocoding API requires you to use the results for displaying on a map... – Josh Sep 03 '15 at 15:26
  • @Josh Are you saying I can't use geocoding API to grab a location for the purposes of determining the timezone at that location? – Cruncher Dec 03 '18 at 19:04
  • 2
    From the policy page: "You can display Time Zone API results on a Google Map, or without a map. If you want to display Time Zone API results on a map, then these results must be displayed on a Google Map. It is prohibited to use Time Zone API data on a map that is not a Google map." https://developers.google.com/maps/documentation/timezone/policies – tmorell Jul 10 '19 at 01:02
4

Ruby gem to convert zip code to timezone: https://github.com/Katlean/TZip (forked from https://github.com/farski/TZip).

> ActiveSupport::TimeZone.find_by_zipcode('90029')
 => "Pacific Time (US & Canada)"

It's fast, small, and has no external dependencies, but keep in mind that zip codes just don't map perfectly to timezones.

mkirk
  • 3,965
  • 1
  • 26
  • 37
  • 1
    Both the original TZip and Katlean's fork are good, but not 100% accurate. Some zip codes (likely introduced in the last few years) are not accounted for. – bigtex777 Jan 22 '16 at 19:04
  • The fork link is dead and the original hasn't been updated for 8 years so this is probably not a good choice. – Casey Jan 14 '21 at 15:38
3

This will download a yaml file that will map all timezones to an array of their zipcodes:

curl https://gist.githubusercontent.com/anonymous/01bf19b21da3424f6418/raw/0d69a384f55c6f68244ddaa07e0c2272b44cb1de/timezones_to_zipcodes.yml > timezones_to_zipcodes.yml

e.g.

"Eastern Time (US & Canada)" => ["00100", "00101", "00102", "00103", "00104", ...]
"Central Time (US & Canada)" => ["35000", "35001", "35002", "35003", "35004", ...]
etc...

If you prefer the shortened timezones, you can run this one:

curl https://gist.githubusercontent.com/anonymous/4e04970131ca82945080/raw/e85876daf39a823e54d17a79258b170d0a33dac0/timezones_to_zipcodes_short.yml > timezones_to_zipcodes.yml

e.g.

"EDT" => ["00100", "00101", "00102", "00103", "00104", ...]
"CDT" => ["35000", "35001", "35002", "35003", "35004", ...]
etc...
BananaNeil
  • 10,322
  • 7
  • 46
  • 66
  • 1
    This includes 96941 (Micronesia) as being in Pacific time, and includes 83500 as a zip code in Pacific time, but I do not believe that exists in the United States. How was the data created? – Justin Blank Sep 02 '16 at 20:25
  • Also there are Puerto Rico zip codes with Eastern Time and that is wrong. – Mike Apr 13 '22 at 15:55
1

In addition to Doug Kavendek answer. One could use the following approach to get closer to tz_database.

  1. Download [Free Zip Code Latitude and Longitude Database]
  2. Download [A shapefile of the TZ timezones of the world]
  3. Use any free library for shapefile querying (e.g. .NET Easy GIS .NET, LGPL).
    var shapeFile = new ShapeFile(shapeFilePath);
    var shapeIndex = shapeFile.GetShapeIndexContainingPoint(new PointD(long, lat), 0D);
    var attrValues = shapeFile.GetAttributeFieldValues(shapeIndex);
    var timeZoneId = attrValues[0];

P.S. Can't insert all the links :( So please use search.

1

See these links for the Olson database:

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
joe snyder
  • 3,629
  • 2
  • 21
  • 13
1

I've been working on this problem for my own site and feel like I've come up with a pretty good solution

1) Assign time zones to all states with only one timezone (most states)

and then either

2a) use the js solution (Javascript/PHP and timezones) for the remaining states

or

2b) use a database like the one linked above by @Doug.

This way, you can find tz cheaply (and highly accurately!) for the majority of your users and then use one of the other, more expensive methods to get it for the rest of the states.

Not super elegant, but seemed better to me than using js or a database for each and every user.

Community
  • 1
  • 1
Matt Parrilla
  • 3,171
  • 6
  • 35
  • 54
0

There's actually a great Google API for this. It takes in a location and returns the timezone for that location. Should be simple enough to create a bash or python script to get the results for each address in a CSV file or database then save the timezone information.

https://developers.google.com/maps/documentation/timezone/start

Request Endpoint:

https://maps.googleapis.com/maps/api/timezone/json?location=38.908133,-77.047119&timestamp=1458000000&key=YOUR_API_KEY

Response:

{
   "dstOffset" : 3600,
   "rawOffset" : -18000,
   "status" : "OK",
   "timeZoneId" : "America/New_York",
   "timeZoneName" : "Eastern Daylight Time"
}
Darwin von Corax
  • 5,201
  • 3
  • 17
  • 28
Anonmily
  • 54
  • 5
0

Also note, that if you happen to be using Yahoo geocoding service you can have timezone information returned to you by setting the correct flag.

http://developer.yahoo.com/geo/placefinder/guide/requests.html#flags-parameter

Chris N
  • 24
  • 3
  • 1
    May have been useful at one time, but Yahoo's great Geocoding service was EOL'd several years ago. – lreeder Mar 04 '19 at 19:13