Reputation: 2498
is there any possibility to determine the timezone of point (lat/lon) without using webservices? Geonames.org is not stable enough for me to use :( I need this to work in PHP.
Thanks
Upvotes: 54
Views: 58258
Reputation: 129
After a lot of searching, the is the only solution that worked for me it's in PHP and it only gets united states timezones
function get_us_timezone($lat, $lon) {
// Define an array of US timezones with their ids, offsets and boundaries
$us_timezones = array(
"America/Adak" => array("offset" => -10, "west" => -180, "east" => -169.3, "north" => 71.4, "south" => 51.2),
"America/Anchorage" => array("offset" => -9, "west" => -169.3, "east" => -129.8, "north" => 71.4, "south" => 51.2),
"America/Boise" => array("offset" => -7, "west" => -114.8, "east" => -111.1, "north" => 49, "south" => 41.9),
"America/Chicago" => array("offset" => -6, "west" => -104.1, "east" => -85.5, "north" => 49, "south" => 24.5),
"America/Denver" => array("offset" => -7, "west" => -114.1, "east" => -100.5, "north" => 49, "south" => 31.3),
"America/Detroit" => array("offset" => -5, "west" => -85.5, "east" => -80.5, "north" => 48.3, "south" => 41.7),
"America/Honolulu" => array("offset" => -10, "west" => -180, "east" => -154.8, "north" => 28.4, "south" => 18.9),
"America/Indiana/Indianapolis" => array("offset" => -5, "west" => -87.6, "east" => -84.8, "north" => 41.8, "south" => 37.8),
"America/Los_Angeles" => array("offset" => -8, "west" => -124.8, "east" => -114.1, "north" => 49, "south" => 32.5),
"America/New_York" => array("offset" => -5, "west" => -80.5, "east" => -66.9, "north" => 47.5, "south" => 24.5),
"America/Phoenix" => array("offset" => -7, "west" => -114.8, "east" => -109, "north" => 37, "south" => 31.3),
"America/Puerto_Rico" => array("offset" => -4, "west" => -67.9, "east" => -65.2, "north" => 18.5, "south" => 17.9)
);
// Loop through the array and check if the given coordinates are within the boundaries of each timezone
foreach ($us_timezones as $id => $zone) {
if ($lat >= $zone["south"] && $lat <= $zone["north"] && $lon >= $zone["west"] && $lon <= $zone["east"]) {
// Return the timezone id
return $id;
}
}
return "America/Los_Angeles";
}
Upvotes: 0
Reputation: 2003
I know this is old, but I spent some time looking for this answer. Found something very useful. Google does time zone lookups by long/lat. No free tier anymore :-/
https://developers.google.com/maps/documentation/timezone/
Upvotes: 8
Reputation: 1506
I ran into this problem while working on another project and looked into it very deeply. I found all of the existing solutions to be lacking in major ways.
Downloading the GeoNames data and using some spatial index to look up the nearest point is definitely an option, and it will yield the correct result a lot of the time, but it can easily fail if a query point is on the wrong side of a time zone border from the nearest point in the database.
A more accurate method is to use a digital map of the time zones and to write code to find the polygon in that map that contains a given query point. Thankfully, there is an excellent map of the time zones of the world available at http://efele.net/maps/tz/world/ (not maintained anymore). To write an efficient query engine, you need to:
Each of those are worthy of their own Stack Overflow question/answer page.
After concluding that none of the existing solutions out there met my needs, I wrote my own solution and made it available here:
AskGeo uses a digital map and has a highly optimized spatial index that allows for running more than 10,000 queries per second on my computer in a single thread. And it is thread safe, so even higher throughput is certainly possible. This is a serious piece of code, and it took us a long time to develop, so we are offering it under a commercial license.
It is written in Java, so using it in PHP would involve using:
http://php-java-bridge.sourceforge.net/doc/how_it_works.php
We are also open to porting it for a bounty. For details on the pricing, and for detailed documentation, see http://askgeo.com.
I hope this is useful. It certainly was useful for the project I was working on.
Upvotes: 10
Reputation: 413
This project builds a shapefile from data from OpenStreetMap and link to multiple libraries that handle it. For PHP you can look at https://github.com/minube/geo-timezone
Upvotes: 0
Reputation: 1
You can get the timezone based on the location in javascript.
function initAutocomplete() {
// Create the autocomplete object, restricting the search to geographical
// location types.
autocomplete = new google.maps.places.Autocomplete(
/** @type {!HTMLInputElement} */(document.getElementById('Location')),
{types: ['geocode']});
// When the user selects an address from the dropdown, populate the address
// fields in the form.
autocomplete.addListener('place_changed', fillInAddress);
}
function fillInAddress() {
// Get the place details from the autocomplete object.
var place = autocomplete.getPlace();
fnGettimezone($('#Location').serialize());
for (var component in componentForm) {
document.getElementById(component).value = '';
document.getElementById(component).disabled = false;
}
// Get each component of the address from the place details
// and fill the corresponding field on the form.
for (var i = 0; i < place.address_components.length; i++) {
var addressType = place.address_components[i].types[0];
if (componentForm[addressType]) {
var val = place.address_components[i][componentForm[addressType]];
document.getElementById(addressType).value = val;
}
}
}
function fnGettimezone(location) {
$.ajax({
url: "http://maps.googleapis.com/maps/api/geocode/json?address=" + location + "&sensor=false",
dataType: 'json',
success: function (result) {
console.log(result);
// result is already a parsed javascript object that you could manipulate directly here
var myObject = JSON.parse(JSON.stringify(result));
lat = myObject.results[0].geometry.location.lat;
lng = myObject.results[0].geometry.location.lng;
console.log(myObject);
$.ajax({
url: "https://maps.googleapis.com/maps/api/timezone/json?location=" + lat + "," + lng + "×tamp=1331161200&sensor=false",
dataType: 'json',
success: function (result) {
// result is already a parsed javascript object that you could manipulate directly here
var myObject = JSON.parse(JSON.stringify(result));
$('#timezone').val(myObject.timeZoneName);
}
});
}
});
}
Upvotes: 0
Reputation: 816
You can use Google Timezone api. https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510×tamp=1331161200&key=YOUR_API_KEY
{
"dstOffset" : 0,
"rawOffset" : -28800,
"status" : "OK",
"timeZoneId" : "America/Los_Angeles",
"timeZoneName" : "Pacific Standard Time"
}
Upvotes: 0
Reputation: 929
I use geocoder.ca
Input any location in North America, Output geocodes, area codes and timezone in json or jsonp.
For example: http://geocoder.ca/1600%20pennsylvania%20avenue,Washington,DC
Area Code: (202) Time Zone: America/New_York
Json:
{"standard":{"staddress":"Pennsylvania Ave","stnumber":"1600","prov":"DC","city":"WASHINGTON","postal":"20011","confidence":"0.8"},"longt":"-76.972948","TimeZone":"America/New_York","AreaCode":"202","latt":"38.874533"}
Upvotes: 0
Reputation: 7374
I downloaded data that matches 5 digit zip codes to time zones, and data that determines the UTC offset for each time zone during DST and non-DST periods.
Then I simplified the data to only consider the first three digits of the ZIP Code, since all ZIP codes that share the first three digits are very close to each other; the three digits identify a unique mail distribution center.
The resulting Json file does require you to decide whether or not you are subject to DST currently, and it probably has some inaccuracy here and there. But it's a pretty good local solution that is very compact and simple to query.
Here it is: https://gist.github.com/benjiwheeler/8aced8dac396c2191cf0
Upvotes: 0
Reputation: 19
Not sure if this is useful or not, but I built a database of timezone shapes (for North America only), which is painstakingly accurate and current not just for borders, but also for daylight saving time observance. Also shapes for unofficial exceptions. So you could query the set of shapes for a given location could return multiple shapes that apply to that location, and choose the correct one for the time of year.
You can see an image of the shapes at http://OnTimeZone.com/OnTimeZone_shapes.gif. Blue shapes are around areas that do not observe daylight saving time, magenta shapes those that do observe daylight saving time, and neon green shapes (small and tough to see at that zoom level) are for areas with unofficial deviation from the official time zone. Lots more detail on that available at the OnTimeZone.com site.
The data available for download at OnTimeZone.com is free for non-commercial use. The shape data, which is not available for download, is available for commercial license.
Upvotes: 1
Reputation: 10468
I've written a small Java class to do this. It could be easily translated to PHP. The database is embedded in the code itself. It's accurate to 22km.
https://sites.google.com/a/edval.biz/www/mapping-lat-lng-s-to-timezones
The whole code is basically stuff like this:
if (lng < -139.5) {
if (lat < 68.5) {
if (lng < -140.5) {
return 371;
} else {
return 325;
}
...so I presume a translation to PHP would be easy.
Upvotes: 2
Reputation: 4861
How exact do your results have to be? If a rough estimate is enough, calculate the offset yourself:
offset = direction * longitude * 24 / 360
where direction is 1 for east, -1 for west, and longitude is in (-180,180)
Upvotes: 23
Reputation: 691
How about this ?
// ben@jp
function get_nearest_timezone($cur_lat, $cur_long, $country_code = '') {
$timezone_ids = ($country_code) ? DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $country_code)
: DateTimeZone::listIdentifiers();
if($timezone_ids && is_array($timezone_ids) && isset($timezone_ids[0])) {
$time_zone = '';
$tz_distance = 0;
//only one identifier?
if (count($timezone_ids) == 1) {
$time_zone = $timezone_ids[0];
} else {
foreach($timezone_ids as $timezone_id) {
$timezone = new DateTimeZone($timezone_id);
$location = $timezone->getLocation();
$tz_lat = $location['latitude'];
$tz_long = $location['longitude'];
$theta = $cur_long - $tz_long;
$distance = (sin(deg2rad($cur_lat)) * sin(deg2rad($tz_lat)))
+ (cos(deg2rad($cur_lat)) * cos(deg2rad($tz_lat)) * cos(deg2rad($theta)));
$distance = acos($distance);
$distance = abs(rad2deg($distance));
// echo '<br />'.$timezone_id.' '.$distance;
if (!$time_zone || $tz_distance > $distance) {
$time_zone = $timezone_id;
$tz_distance = $distance;
}
}
}
return $time_zone;
}
return 'none?';
}
//timezone for one NY co-ordinate
echo get_nearest_timezone(40.772222,-74.164581) ;
// more faster and accurate if you can pass the country code
echo get_nearest_timezone(40.772222, -74.164581, 'US') ;
Upvotes: 4
Reputation: 111
You can use time zone boundaries, provided here:
http://www.opensource.apple.com/source/TimeZoneData/
Upvotes: 1
Reputation: 8763
Another solution is to import a table of cities with timezones and then to use the Haversine formula to find the nearest city in that table, relevant to your coordinates. I have posted a full description here: http://sylnsr.blogspot.com/2012/12/find-nearest-location-by-latitude-and.html
For an example of loading the data in MySQL, I have posted an example here (with sources for downloading a small data dump): http://sylnsr.blogspot.com/2012/12/load-timezone-data-by-city-and-country.html
Note that the accuracy of the look-up will be based on how comprehensive your look-up data is.
Credits and References: MySQL Great Circle Distance (Haversine formula)
Upvotes: 1
Reputation: 511
For areas on land, there are some shapefile maps that have been made for the timezones of the tz (Olson) database. They're not updated quite as regularly as the tz database itself, but it's a great starting point and seems to be very accurate for most purposes.
Upvotes: 5
Reputation: 346377
I had this problem a while back and did exactly what adam suggested:
IIRC it took less than 1 second to populate the R-Tree, and it could then perform thousands of lookups per second (both on a 5 year old PC).
Upvotes: 58
Reputation: 36236
You should be able to, if you know the polygon of the timezone to see if a given lat/lon is inside it.
Latitude/Longitude Polygon Data
Upvotes: 5
Reputation: 443
Unfortunately, time zones are not regular enough for some simple function. See the map in Wikipedia - Time Zone
However, some very rough approximation can be calculated: 1 hour difference corresponds to 15 degrees longitude (360 / 24).
Upvotes: 1