Ruby gem for finding timezone of location
You can easily get a latitude and longitude using the google maps geocoding API. There are ruby implementations for the API like GeoKit. Once you have that you can use the timezone gem to easily get the timezone of a latitude and longitude. The gem makes it easy to do time conversions in your timezone as well.
Here is an example using GeoKit and TimeZone.
require 'geokit'
require 'timezone'
res = Geokit::Geocoders::GoogleGeocoder.geocode('140 Market St, San Francisco, CA')
timezone = Timezone::Zone.new(:latlon => res.ll)
timezone.zone
=> "America/Los_Angeles"
timezone.time Time.now
=> 2011-12-01 14:02:13 UTC
get timezone from location name in Ruby on Rails
You could download the geonames db and compare lat/lng to the nearest place (with timezone) in the db
- Download the database of cities from geonames.org
- convert it to a compact lat/lon -> timezone list
How to get Timezone with geocode gem?
You cannot get timezone directly from geocoder gem.
It can just give you location.
You can use the gem below to get the timezone for a particular zone or for (lat,long) values.
https://github.com/panthomakos/timezone
timezone = Timezone::Zone.new :latlon => [-34.92771808058, 138.477041423321]
timezone.zone
=> "Australia/Adelaide"
timezone.time Time.now
=> 2011-02-12 12:02:13 UTC
How do I get the utc offset from an address?
Geolocate the address to lat/lon coordinates using any number of web services for this. Then see the options in How to get a time zone from a location using latitude and longitude coordinates? The Ruby gem that Yevgeniy mentioned is listed there, along with other options.
Don't try to get an offset for the location - it could change periodically for DST. Get the time zone instead, such as Asia/Singapore
or America/New_York
. Then use that to determine the offset for a particular point in time.
See "Time Zone != Offset" in the timezone tag wiki.
Linking datetimes of events to their associated location timezone (TimeZone gem, ActiveSupport::TimeWithZone)
User enters a datetime (year, month, day, hour, min, sec) in the appropriate local time for the event location. To save this as the correct UTC time in your DB, and retrieve later retrieve it and use it with its correct timezone, here's the recipe:
You must first set
Time.zone = timezone
-- where timezone is a named timezone string, like"America/Toronto"
(GeoKit/TimeZone style) or"Eastern Time (US & Canada)"
(Rails 3 style):1.9.3p200 :001 > Time.zone = "America/Toronto"
=> "America/Toronto"Note that it is nontrivial to map between the GeoKit/TimeZone style and the Rails 3 style. There is some support for that, but many of the mappings that GeoKit returns are not in the Rails mappings, so I'm sticking with the GeoKit/TimeZone names because they seem to work just fine, and I don't need user-selectable timezones because I'm taking care of all of that automagically for the user using the locations.
Now you can parse and save your datetime variable using
ActiveSupport::TimeWithZone
, and it will be encoded properly using theTime.zone
parameter:1.9.3p200 :002 > t = Time.zone.local( 2012, 8, 1, 12, 0, 0 )
=> Wed, 01 Aug 2012 12:00:00 EDT -04:00i.e. In my case, for my
Event
model with instanceevent
:event.start = Time.zone.local( year, month, day, hour, min, sec )
event.saveWhen the data is saved to the DB, it is in UTC:
2012-08-01 16:00:00.000000
(Simulated below with call to
t.utc
)1.9.3p200 :003 > t = t.utc
=> 2012-08-01 16:00:00 UTC
1.9.3p200 :004 > t.zone
=> "UTC"Now, when you read it back from the DB, you need to again use the
TimeWithZone
support to tell the DateTime what timezone it is in.Note that the
in_time_zone
function does not change the underlying datetime variable's timezone:1.9.3p200 :005 > t.in_time_zone( "America/Toronto" )
=> Wed, 01 Aug 2012 12:00:00 EDT -04:00
1.9.3p200 :006 > t
=> 2012-08-01 16:00:00 UTC
1.9.3p200 :007 > t.zone
=> "UTC"so you really need to assign the function output back to your datetime variable:
1.9.3p200 :008 > t = t.in_time_zone( "America/Toronto" )
=> Wed, 01 Aug 2012 12:00:00 EDT -04:00
1.9.3p200 :009 > t
=> Wed, 01 Aug 2012 12:00:00 EDT -04:00
1.9.3p200 :010 > t.zone
=> "EDT"Finally, a warning -- do not use
t.time
! It's output is completely useless and irrational, with the time and it's timezone out of sync:1.9.3p200 :011 > t.time
=> 2012-08-01 12:00:00 UTC
Getting timezone in pure Ruby (no rails)
For the time being, this works
TZ=Asia/Kolkata ruby -e "p Time.new(1942).strftime('%z')"
Setting the TZ
environment variable also works from within Ruby: (seen in test_time_tz.rb
)
def with_tz(tz)
old = ENV['TZ']
ENV['TZ'] = tz
yield
ensure
ENV['TZ'] = old
end
with_tz('Asia/Kolkata') do
(1935..1945).each do |x|
puts "#{x} => #{Time.local(x).strftime('%z')}"
end
end
How to get a time zone from a location using latitude and longitude coordinates?
Time Zone Location Web Services
- Google Maps Time Zone API
- Bing Maps Time Zone API
- Azure Maps Time Zone API
- GeoNames Time Zone API
- TimeZoneDB API
- AskGeo - commercial (but arguably more accurate than GeoNames)
- GeoGarage Time Zone API - commercial, focusing on Nautical time zones.
Raw Time Zone Boundary Data
- Timezone Boundary Builder - builds time zone shapefiles from OpenStreetMaps map data. Includes territorial waters near coastlines.
The following projects have previously been sources of time zone boundary data, but are no longer actively maintained.
- tz_world - the original shapefile data from Eric Muller
- whereonearth-timezone - GeoJSON version with WOEDB data merged in
Time Zone Geolocation Offline Implementations
Implementations that use the Timezone Boundary Builder data
- node-geo-tz - JavaScript library (Node.js only)
- timespace - JavaScript library
- tz-lookup-oss - JavaScript library
- GeoTimeZone - .NET library
- Geo-Timezone - PHP library
- timezonefinder - Python library
- ZoneDetect - C library
- Timeshape - Java library
- TimeZoneMap - Java and Android library
- lutz - R library
- go-tz - Go library
- Timezone lookup - Go library
- docker-timezone-lookup - docker container wrapping node-geo-tz
Implementations that use the older tz_world data
- latlong - Go library (Read this post also.)
- TimeZoneMapper - Java library
- tzwhere - JavaScript/Node library
- pytzwhere - Python library
- timezone_finder - Ruby library
- LatLongToTimeZone - Java and Swift libraries
- What Time is it here? - Blog post describing PHP and MongoDB
- rundel/timezone - R library
Libraries that call one of the web services
- timezone - Ruby gem that calls GeoNames
- AskGeo has its own libraries for calling from Java or .Net
- GeoNames has client libraries for just about everything
Self-hosted web services
- geo2tz - based on Timezone lookup, available via Docker image
Other Ideas
- Find the nearest city with an R-Tree
- Find the nearest city with MySQL
Please update this list if you know of any others
Also, note that the nearest-city approach may not yield the "correct" result, just an approximation.
Conversion To Windows Zones
Most of the methods listed will return an IANA time zone id. If you need to convert to a Windows time zone for use with the TimeZoneInfo
class in .NET, use the TimeZoneConverter library.
Don't use zone.tab
The tz database includes a file called zone.tab
. This file is primarily used to present a list of time zones for a user to pick from. It includes the latitude and longitude coordinates for the point of reference for each time zone. This allows a map to be created highlighting these points. For example, see the interactive map shown on the moment-timezone home page.
While it may be tempting to use this data to resolve the time zone from a latitude and longitude coordinates, consider that these are points - not boundaries. The best one could do would be to determine the closest point, which in many cases will not be the correct point.
Consider the following example:
The two squares represent different time zones, where the black dot in each square is the reference location, such as what can be found in zone.tab. The blue dot represents the location we are attempting to find a time zone for. Clearly, this location is within the orange zone on the left, but if we just look at closest distance to the reference point, it will resolve to the greenish zone on the right.
Related Topics
Best Practices For Reusing Code Between Controllers in Ruby on Rails
How to Use Global Variables or Constant Values in Ruby
Can You Ask Ruby to Treat Warnings as Errors
Ruby/Rails - Change the Timezone of a Time, Without Changing the Value
Cannot Use Rvm-Installed Ruby With Sudo
Convert Unicode Codepoint to String Character in Ruby
How to Update Ruby to 1.9.X on Mac
Serving Static Files With Sinatra
Getting Fields_For and Accepts_Nested_Attributes_For to Work With a Belongs_To Relationship
How to Capture Stdout to a String
Difference Between Print and Puts
Why Not Use Shared Activerecord Connections For Rspec + Selenium
How to Use "Gets" and "Gets.Chomp" in Ruby