87

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

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

我找到了很多邮政编码数据库,到目前为止只有少数包含时区信息,但那些不是免费的,比如这个。如果绝对有必要为此付费订阅一项服务,那么这是不值得的,我们只需要明确询问用户即可。

尽管语言不是特别相关,因为我可能可以根据需要进行转换,但我们使用的是 PHP 和 MySQL。

4

12 回答 12

35

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

于 2010-03-16T17:59:09.730 回答
29

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

通过结合这些事实,您可以快速得出自己的每个 zip 时区列表。

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

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

您正在处理的大多数非美国国家/地区可能恰好位于一个时区(同样,也有例外)。根据您的需要,您可能希望查看前 N 个非美国访问者来自哪里,然后查找他们的时区。

于 2010-03-16T16:50:46.313 回答
15

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

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

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

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

于 2012-04-24T18:23:11.307 回答
9

如果你愿意,你也可以通过询问浏览器来感受时区 Josh Fraser在这里有一篇很好的文章

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)。由于夏季总是观察到 DST,我们可以将 1 月两个日期之间的时间偏移量与 6 月两个日期之间的时间偏移量进行比较。如果偏移量不同,则我们知道该位置遵守 DST。如果偏移量相同,那么我们知道该位置不遵守 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
}

这一切都归功于乔什·弗雷泽。

这可能会帮助您与美国以外的客户打交道,并且可能会补充您的 zip 方法。

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

于 2010-03-16T16:55:32.120 回答
6

谷歌为此有一个特定的 API: https ://developers.google.com/maps/documentation/timezone/

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

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

它们需要查询字符串上的 unix 时间戳。从返回的响应来看,它似乎timeZoneName考虑了夏令时,基于时间戳,同时timeZoneId是一个与 DST 无关的时区名称。

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

我相信对于 PHP,您同样可以在http://pecl.php.net/package/timezonedb中找到“America/New_York”

于 2014-09-01T17:06:43.220 回答
4

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

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

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

于 2012-05-16T17:10:07.940 回答
2

这将下载一个 yaml 文件,该文件将所有时区映射到其邮政编码的数组:

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

例如

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

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

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

例如

"EDT" => ["00100", "00101", "00102", "00103", "00104", ...]
"CDT" => ["35000", "35001", "35002", "35003", "35004", ...]
etc...
于 2015-06-08T02:42:42.560 回答
1

我一直在为自己的网站解决这个问题,感觉我想出了一个很好的解决方案

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

然后要么

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

或者

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

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

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

于 2011-07-04T23:00:36.960 回答
1

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

  1. 下载【免费邮编经纬度数据库】
  2. 下载 [世界 TZ 时区的 shapefile]
  3. 使用任何免费库进行 shapefile 查询(例如.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];

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

于 2014-09-26T18:31:52.137 回答
0

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

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

于 2011-10-19T20:21:43.647 回答
0

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

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

请求端点:

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

回复:

{
   "dstOffset" : 3600,
   "rawOffset" : -18000,
   "status" : "OK",
   "timeZoneId" : "America/New_York",
   "timeZoneName" : "Eastern Daylight Time"
}
于 2016-06-12T16:20:05.060 回答