35

I am trying to get the time zones for latitude and longitude coordinates but am having a few problems The mistakes are probably very basic

I have a table in a database with around 600 rows. Each row contains a lat long coordinate for somewhere in the world I want to feed these co-ordinates into a function and then retrieve the time zone. The aim being to convert events which have a local time stamp within each of these 600 places into UTC time

I found a blog post which uses a piece of code to derive timezones from geographical coordinates.

When I try to run the code, I get the error geonames is not defined. I have applied for an account with geonames.

I think I have just saved the function file in the wrong directory or something simple. Can anyone help

#-------------------------------------------------------------------------------
# Converts latitude longitude into a time zone
# REF: https://gist.github.com/pamelafox/2288222
# REF: http://blog.pamelafox.org/2012/04/converting-addresses-to-timezones-in.html
#-------------------------------------------------------------------------------

geonames_client = geonames.GeonamesClient('Username_alpha')
geonames_result = geonames_client.find_timezone({'lat': 48.871236, 'lng': 2.77928})
user.timezone = geonames_result['timezoneId']
martineau
  • 119,623
  • 25
  • 170
  • 301
John Smith
  • 2,448
  • 7
  • 54
  • 78
  • 5
    You don't seem to have *imported* `geonames`. Add a `import geonames` line? – Martijn Pieters Apr 01 '13 at 11:07
  • 1
    related: [Get Timezone from City in Python/Django](http://stackoverflow.com/q/16505501/4279), see [`pytzwhere` example in my answer](http://stackoverflow.com/a/16519004/4279). – jfs May 15 '14 at 19:19

4 Answers4

40

With tzwhere and pytz:

import datetime
import pytz
from tzwhere import tzwhere

tzwhere = tzwhere.tzwhere()
timezone_str = tzwhere.tzNameAt(37.3880961, -5.9823299) # Seville coordinates
timezone_str
#> Europe/Madrid

timezone = pytz.timezone(timezone_str)
dt = datetime.datetime.now()
timezone.utcoffset(dt)
#> datetime.timedelta(0, 7200)
tuxayo
  • 1,150
  • 1
  • 13
  • 20
  • 1
    It worked as an off-line solution we needed. Although some may encounter an error: OSError: Could not find lib geos_c or load any of its variants when importing tzwhere. This helped: http://stackoverflow.com/a/23057508/3699126 – sunsetjunks Mar 28 '17 at 14:31
  • doesnt work in mac os x sierra and python 2.7 – Ciasto piekarz Jul 31 '17 at 14:00
  • 1
    Any additional detail? Message error? Can you try with Python 3? – tuxayo Jul 31 '17 at 17:34
  • 1
    no error, `None` is returned calling `tzNameAt` method – Ciasto piekarz Aug 02 '17 at 17:53
  • This worked for me in High Sierra and Python 2.7 – Jan S. Jan 11 '18 at 16:27
  • @Ciastopiekarz What were the arguments of your call to tzNameAt? If you still can find them. Maybe it's normal that some coordinates make tzNameAt() return None? – tuxayo Apr 30 '18 at 19:17
  • For those facing this error in Mac OS: AttributeError: 'tzwhere' object has no attribute 'tzwhere' replace tzwhere = tzwhere.tzwhere() with tz = tzwhere.tzwhere(), use timezone_str = tz.tzNameAt(37.3880961, -5.9823299) in the next line. – Trees Jun 16 '20 at 10:22
  • `tzwhere ` appears to not be available in Python 3, as per [this question](https://stackoverflow.com/questions/45019641/using-tzwhere-module-in-python-3) – tsherwen Sep 22 '20 at 12:43
  • very strange: for me it works the first time then if a call again tzwhere.tzwhere() I get: AttributeError: 'tzwhere' object has no attribute 'tzwhere' – kolergy Dec 19 '21 at 12:43
23

I was able to do a lookup suitable for my purposes using timezonefinder:

import datetime
import timezonefinder, pytz

tf = timezonefinder.TimezoneFinder()

# From the lat/long, get the tz-database-style time zone name (e.g. 'America/Vancouver') or None
timezone_str = tf.certain_timezone_at(lat=49.2827, lng=-123.1207)

if timezone_str is None:
    print("Could not determine the time zone")
else:
    # Display the current time in that time zone
    timezone = pytz.timezone(timezone_str)
    dt = datetime.datetime.utcnow()
    print("The time in %s is %s" % (timezone_str, dt + timezone.utcoffset(dt)))

There's a discussion of the methods of timezonefinder and its limitations in the documentation linked from its pypi page.

timezonefinder and pytz can be found in the pip packages of the same name.

rakslice
  • 8,742
  • 4
  • 53
  • 57
  • 2
    I haven't done a comprehensive test with multiple input coordinates, so I can't speak to the accuracy, but speed-wise timezonefinder is _much_ faster than tzwhere. For me, at least. – Jim Carr May 02 '18 at 00:53
  • This is the most up to date answer here, but for posterity, it really is worth looking at this link which is regularly updated: https://stackoverflow.com/questions/16086962/how-to-get-a-time-zone-from-a-location-using-latitude-and-longitude-coordinates – stephan Aug 01 '22 at 03:12
6

This works as expected:

import geonames
geonames_client = geonames.GeonamesClient('demo')
geonames_result = geonames_client.find_timezone({'lat': 48.871236, 'lng': 2.77928})
print geonames_result['timezoneId']

Output:

'Europe/Paris'
Manu
  • 3,212
  • 1
  • 16
  • 14
1
import requests
lat = 48.871236 ## your latitude
lon = 2.77928 ## your longitude

url = "http://api.geonames.org/timezoneJSON?formatted=true&lat={}&lng={}&username=demo".format(lat,lon)

r = requests.get(url) ## Make a request
return r.json()['timezoneId'] ## return the timezone
Berk
  • 338
  • 5
  • 11
Bilal
  • 517
  • 5
  • 7
  • 1
    It works great. However, is there any hit limits for the use of this webservice? – Diansheng Jul 18 '17 at 08:08
  • 1
    This is what I received ```{'status': {'message': 'the daily limit of 20000 credits for demo has been exceeded. Please use an application specific account. Do not use the demo account for your application.', 'value': 18}}``` :) – VivienG Jul 20 '20 at 20:39
  • With python 3.8 for me the error is `KeyError: 'timezoneId'` – duff18 Sep 15 '20 at 19:58