Detecting Timezone By IP
Through Planet PHP I found an article on Pre-populating forms with the timezone . I'd normally add a comment instead, but the comment would almost be larger then the original post, so I am instead writing up an entry myself. The post describes several ways to obtain the user's timezone and use that to pre-fill a form. None of them are working properly though. I'll try to explain for each of them why not, but first of all it is important to know what a timezone actually is.
A timezone is a set of rules that determines the UTC offset for different times around the year for a specific location. Because of daylight savings time, a specific location can have two (or more) different UTC offsets depending on what point in time you look at it. Some areas might have had different rules in the past, even in the same country. An example here is China, where currently there is only one timezone, but previously there were multiple. Thus there are different timezones for the different locations in China, even though the current UTC offset is the same for all of them. Timezones are identified by Country/City or Country/Subcountry/City.
The offering by MaxMind allows you to link a country/region combination to Timezone identifier. For the US it subdivides this per state even. However, it misses the different timezones for Russia, Australia and even Indiana, USA.
IP2Location only provides a single UTC offset per IP range, totally ignoring daylight savings time.
The Hostip.info solution I can't access because phpclasses requires some stupid registration.
As for the author's own solution, using JavaScript, is flawed at least partly as well. In his example JavaScript only returns a UTC offset. Luckily it is possible to detect the correct timezone quite a bit better by using some of PHP's functionality. The following bit of code uses both the UTC offset and the timezone abbreviation to find out the user's timezone:
<?php
if (!isset($_GET['tzinfo'])) {
?>
<html>
<script type="text/javascript">
var d = new Date()
var tza = d.toLocaleString().split(" ").slice(-1)
var tzo = d.getTimezoneOffset()
window.location = window.location + '?tzinfo=' + tza + '|' + tzo
</script>
</html>
<?php
} else {
list( $abbr, $offset ) = explode( '|', $_GET['tzinfo']);
echo timezone_name_from_abbr( $abbr, $offset * -60 );
}
?>
This is still not perfect of course, because it would for example give the same result for most of Europe (Europe/Berlin).
Figuring out the user's timezone can be done by using a high-accuracy database of IPs to lat/longitudes such as hostip.info and MaxMind offer, as well as a mapping from location to timezone. The latter however, is not available as far as I know. If however a data file that has proper definitions of the different timezone boundaries exist (mostly, on a per-province level would be enough), then such a tool can be easily build. I saw that OpenStreetMap has such a map, but I can't really find the raw data for that unfortunately. It would however, be awesome to have such a data file.
Comments
http://www.geonames.org/ you can get the Olson timezones for any just about any city you can think of, or even just an longitude and latitude
@Avi: that is just brilliant. Even better is that you can download the file.
I commented last night but it doesn't seem to have shown up so here goes again . . .
The 'hostip.info' solution used a phpclasses script which used two web services to go from a location to a lat/long (Yahoo) and then from lat/long to a timezone (geonames). Maxmind could just as easily be used to provide the initial location though it would waste the code they've already created.
geonames is a really interesting service though it does need to be pointed out their service only gives the offsets at two times in the year. The dates when DST kicks in around the world are not the same universally so there will be days/weeks when some ambiguity exists.
I had some problems with your code. Firstly copying and pasting didn't seem to work. Everything seemed to end up on one line. Secondly, I get URLs like /rethans.php?tzinfo=10:57:34|-60. Looking at your code I think you were expecting a timezone abbreviation to be in there. I can find no examples online which show that behaviour for toLocaleString() though. What system/browser did you test this on?
I added a short fragment of this post to a comment on the original post. I think this is definitely worth a read and as no trackback was sent to my blog a comment seemed the best way to highlight that the conversation was continued here.
For simply just localizing dates, can just output all the dates in RFC1123 format, then parse() & toLocaleString() in javascript.
Your function takes timezone abbreviation as a parameter. But how do I obtain the timezone abbreviation?
There is the World Time Engine Local Time API that includes an 'IP to Local Time' call.
This sounds exactly like the problem you're having - determining a user's local time without using client-side scripting like Javascript.
I beleive they also have a free trial system where you can try the API for free too.
Life Line
A little quiz.
Do you reckon that this reply is LLM-generated, or not?
Updated 2 pubs
Fix merging into master in automated upgrade script
Merge branch 'v2022'
Update data to 2026d
I hiked 2.0km in 54m55s
I hiked 7.4km in 4h45m01s
I hiked 5.5km in 4h19m08s
Updated a restaurant, a pub, and a hotel; Deleted a resort; Confirmed a farm shop
I hiked 1.3km in 1h1m31s
I hiked 1.9km in 1h52m56s
I hiked 2.9km in 2h55m04s
I hiked 1.6km in 1h16m55s
I hiked 4.8km in 1h22m37s
Specify whether pitches are lit
Survey whether benches have backrests
Specify what can be recycled in recycling containers
Specify type of recycling amenities
Survey postbox collection times
Determine whether any glass or just glass bottles can be recycled here
Specify whether bicycles can be charged at charging stations
Specify whether pedestrian crossings have islands
Specify whether pedestrian crossings have traffic signals
Specify parking types

Shortlink
This article has a short URL available: https://drck.me/dtbi-6bk