关于时区:将美国邮政编码映射到时区

Mapping US zip code to time zone

当用户在我们的应用程序中注册时,我们可以在我们针对国家数据库验证邮政编码时推断他们的邮政编码。从这个邮政编码确定他们的时区的潜在猜测的最佳方法是什么?

我们正在努力减少我们明确要求他们提供的数据量。如果我们的最佳猜测是错误的,他们将能够稍后手动设置时区。我发现邮政编码无助于搞清楚美国以外的时区,但在这种情况下我们不得不手动询问,而且无论如何我们主要与美国打交道。

我发现了很多邮政编码数据库,到目前为止只有少数包含时区信息,但那些不是免费的,比如这个。如果为了做到这一点而必须支付订阅服务,那么它就不值得了,我们只需要明确询问用户。

虽然语言不是特别相关,因为我可以转换所需的东西,但我们使用的是PHP和MySQL。


我刚刚找到一个免费的zip数据库,其中包括时间偏移和参与夏令时。我喜欢Erik J的答案,因为它可以帮助我选择实际时区而不是偏移(因为你永远不能完全确定规则),但我想我可能会从这开始,并尝试根据偏移/ dst配置找到最佳时区匹配。我想我可能会尝试设置一个简单版本的Development 4.0的答案来检查我从zip信息中得到的作为一个完整性测试。这绝对不是我希望的那么简单,但组合应该让我至少90%确定用户的时区。


大多数州都在一个时区(尽管有一些例外)。大多数邮政编码不跨越州界(尽管有一些例外)。

您可以通过组合这些事实快速找出每个zip的时区列表。

这是每个州的邮政编码范围列表,以及每个时区的州列表。

您可以使用此链接或Google地球查看邮政编码的边界并与时区地图进行比较,以将拉链映射到按时区线划分的州的时区。

您正在处理的大多数非美国国家可能只属于一个时区。您可能想要查看前N名非美国访客的来源,并查看他们的时区。


我创建了一个开源(MIT许可)MySQL数据库表,交叉引用邮政编码和时区,并将其上传到sourceforge.net:

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

它来自四个地点(主要的Yahoo PlaceFinder API - 感谢@Chris N)

有关更多信息和说明,请参阅自述文件。


如果您愿意,还可以通过询问浏览器来了解时区
Josh Fraser在这里写了一篇很好的文章

1
2
3
4
5
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);

您需要知道的第二件事是该位置是否遵守夏令时(DST)。由于夏季期间始终遵守夏令时,我们可以将1月份两个日期之间的时间偏差与6月份两个日期之间的时间偏差进行比较。如果偏移量不同,那么我们知道该位置遵守DST。如果偏移量相同,那么我们知道该位置没有观察到DST。

1
2
3
4
5
6
7
8
9
10
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
}

所有这一切归功于Josh Fraser。

这可能会帮助您在美国以外的客户,它可能会补充
你的拉链方式。

这是一个涉及从javascript获取时区的SO问题


Google有一个特定的API:
https://developers.google.com/maps/documentation/timezone/

例如:
https://maps.googleapis.com/maps/api/timezone/json?location=40.704822,-74.0137431×tamp=0

1
2
3
4
5
6
7
{
  dstOffset: 0,
  rawOffset: -18000,
  status:"OK",
  timeZoneId:"America/New_York",
  timeZoneName:"Eastern Standard Time"
}

它们需要查询字符串上的unix时间戳。从返回的响应中可以看出timeZoneName考虑了基于时间戳的夏令时,而timeZoneId是时区的与DST无关的名称。

对于我的使用,在Python中,我只是传递timestamp=0并使用timeZoneId值从pytz获取tz_info对象,然后我可以使用它来在我自己的代码中本地化任何特定的日期时间。

我相信PHP同样你可以在http://pecl.php.net/package/timezonedb找到"America / New_York"


Ruby gem将邮政编码转换为时区:https://github.com/Katlean/TZip(从https://github.com/farski/TZip分叉)。

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

它速度快,体积小,没有外部依赖性,但请记住,邮政编码不能完美映射到时区。


我最近制作了美国所有zipcodes的Ruby哈希值及其相关的时区,如果你有兴趣可以使用它们。为了您的目的,应该很容易进行逆向工程。


我维护一个名为Zipgenius的zipcode-to-timezone API,它使用上面提供的@chriv提供的数据。随意使用它以满足您的需求。


除了Doug Kavendek的回答。可以使用以下方法来接近tz_database。

  • 下载[免费邮编纬度和经度数据库]
  • 下载[世界TZ时区的形状文件]
  • 使用任何免费库进行shapefile查询(例如.NET Easy GIS .NET,LGPL)。
  • 1
    2
    3
    4
        var shapeFile = new ShapeFile(shapeFilePath);
        var shapeIndex = shapeFile.GetShapeIndexContainingPoint(new PointD(long, lat), 0D);
        var attrValues = shapeFile.GetAttributeFieldValues(shapeIndex);
        var timeZoneId = attrValues[0];

    附:无法插入所有链接:(所以请使用搜索。


    我一直在为自己的网站解决这个问题,感觉我已经找到了一个非常好的解决方案

    1)将时区分配给只有一个时区的所有状态(大多数状态)

    然后要么

    2a)对剩余的状态使用js解决方案(Javascript / PHP和时区)

    要么

    2b)使用像@Doug上面链接的数据库。

    通过这种方式,您可以为大多数用户找到便宜(并且非常准确!)的tz,然后使用其他更昂贵的方法之一来获取其他州。

    不是超级优雅,但对我来说似乎比为每个用户使用js或数据库更好。


    请参阅Olson数据库的以下链接:

    • http://en.wikipedia.org/wiki/Tz_database
    • ftp://ftp.iana.org/tz/tz-link.html(是的,ftp) http://www.twinsun.com/tz/tz-link.htm
    • ftp://ftp.iana.org/tz/releases ftp://elsie.nci.nih.gov/pub/
    • https://iana.org/time-zones


    实际上有一个很棒的Google API。它接收一个位置并返回该位置的时区。应该足够简单,可以创建一个bash或python脚本来获取CSV文件或数据库中每个地址的结果,然后保存时区信息。

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

    请求端点:

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

    响应:

    1
    2
    3
    4
    5
    6
    7
    {
      "dstOffset" : 3600,
      "rawOffset" : -18000,
      "status" :"OK",
      "timeZoneId" :"America/New_York",
      "timeZoneName" :"Eastern Daylight Time"
    }

    这将下载一个yaml文件,该文件将所有时区映射到其zipcodes数组:

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

    例如

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

    如果你更喜欢缩短的时区,你可以运行这个:

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

    例如

    1
    2
    3
    "EDT" => ["00100","00101","00102","00103","00104", ...]
    "CDT" => ["35000","35001","35002","35003","35004", ...]
    etc...


    另请注意,如果您碰巧使用Yahoo地理编码服务,则可以通过设置正确的标志来返回给您的时区信息。

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