Find timezone from latitude & longitude in ruby using timezone gem


Context

For one of our client applications, we had a situation where we wanted to identify the timezone of a location. We had the geocode location ie. latitude and longitude and wanted to find the timezone of the location. Since we already had the geocode location we could determine the timezone without explicitly having the user to enter it.

Implementations

Timezone gem

Another approach was making use of the timezone gem. In addition to other timezone related features, it supports exactly what we need. Timezone gem as name suggests supports timezone calculations and in addition to that also supports finding timezone based on latitude and longitude. Its makes use of third party service access like Google Geo API or Genonames, to perform this lookup.

Google API configuration

To configure timezone gem to use Google API, we need to setup Google API by setting up a new project and then get the API key for the selected project. Then we need to enable the Google Timezone API from the API Library. To configure the timezone gem to use Google API, create timezone.rb in config/initializers:

Timezone::Lookup.config(:google) do |c|
  c.api_key = 'google_api_key_goes_here'
  c.client_id = 'google_client_id' # if using 'Google for Work'
end

In our Application, we already made use of Google Geo API elsewhere, hence we ended up using this approach.

Geonames API configuration

We can also use Geonames API for performing lookups. To configure timezone gem to use with Geonames API, we need to have an account on Geonames first, and then we need to enable webservices to be able to use the API. To configure we create a timezone.rb in config/initializers:

Timezone::Lookup.config(:geonames) do |c|
  c.username = 'your_geonames_username_goes_here'
end
Using lookup

Once the API is configured, we can perform the lookup using the Timezone.lookup method simply by passing latitude and longitude to it.

[1] pry(main)> timezone = Timezone.lookup(18.523185, 73.879664)
=> #<Timezone::Zone name: "Asia/Calcutta">
[2] pry(main)> timezone.time_with_offset(Time.now)
=> 2019-08-30 12:10:19 +0530

In our application, once the timezone was identified in this manner, we could simply persist it to the database for future reference.