简体   繁体   中英

Rails timezone from offset

So it seems rails has pretty nice support for timezones, but I've run into a requirement that I'm hoping has already been solved and I'm just not seeing it in the api.

I'd like to be able to find a TimeZone based on an offset. The reason being I'm hooking up to an api that gives me back the users time zone as an offset and don't want to necessarily reinvent the wheel turning that offset into a Rails TimeZone so the rest of the app can use it properly.

Any suggestions? Thanks for the help!

You can get a timezone using the [] method on ActiveSupport::TimeZone . You can either pass a timezone name, hour offset or second offset. For instance:

ActiveSupport::TimeZone["America/Los_Angeles"]                              
 => (GMT-08:00) America/Los_Angeles
ActiveSupport::TimeZone[-8]                              
 => (GMT-08:00) America/Los_Angeles

But keep in mind that an offset is not equivalent to a timezone since multiple timezones can be on the same offset on any one day.

Bit of a hack - but I was using Google's Places API to look up a location for a User, and that gave me the UTC offset in mins. So I wanted to present only the relevant time zones for that location, since there are many for one UTC offset. Further, Rails' TimeZone helper doesn't calculate Daylight Savings and other dynamic offsets. So I included one hour plus and minus to get all relevant time zones, without hopefully overwhelming the user.

Google returns the offset in minutes but Rails wants seconds. As an example, for a location in California we would have an offset (from Places API) of -420 mins for Summer.

offset = -420*60 # convert mins to secs
offset_range = (offset-3600)..(offset+3600)
timezones = ActiveSupport::TimeZone.all.select{|tz| offset_range.include?(tz.utc_offset)}

I then set these timezones as priority zones in Rails' time_zone_select.

The problem with the accepted answer is that it unfortunately does not handle cases where two different timezones have the same utc offset.

For example -7 could be referring to Arizona or Denver which are two DIFFERENT times zones ("America/Phoenix" and "America/Denver"), because Arizona does not observe daylight savings time.

ActiveSupport::TimeZone[-7] returns only one of those two valid timezones.

I needed the same functionality in the slightly simpler case of a database of USA zipcodes which includes a UTC hours offset and Y/N field indicating if it participates in daylight savings time, so West coast USA zipcodes in this database all have "-8" and "Y".

I could not find a built-in Rails method to do it, so I manually created a lookup hash where the key is the UTC & DST fields catenated, eg, "#{utc}#{dst}" and the value is the timezone name. This method could work for utc offsets such as "5.5" (India) as well.

In the method that does the lookup is given the utc and dst values, I specify a default timezone (USA west coast for example) in the case where the hash lookup returns nil because an unexpected value such as "-5N" (since the east coast does not have any non-DST states that should never occur).

But the same method could be applied globally by creating a hash that represented all the possible timezone with both Y and N values for daylight savings time.

class MyZip

HOUR_DST_TO_TIMEZONE_NAME = {
  "-5Y" => "Eastern Time (US & Canada)",
  "-6Y" => "Central Time (US & Canada)",
  "-7Y" => "Mountain Time (US & Canada)",
  "-7N" => "Arizona",
  "-8Y" => "Pacific Time (US & Canada)",
  "-9Y" => "Alaska",
  "-10N" => "Hawaii"
  }

def self.timezone_name_from_zip_hour_dst(utc, dst)
  key = "#{utc}#{dst}" 
  return HOUR_DST_TO_TIMEZONE_NAME[key] || MyZip.unknown_timezone_name
end
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM