Home > Net >  How to find the time zone by an offset abbreviation in Rails?
How to find the time zone by an offset abbreviation in Rails?

Time:11-08

If I have an offset abbreviation like EDT, then how can I find the zone it belongs to?

irb(main):001:0> Time.find_zone("EDT")
=> nil
irb(main):002:0> ActiveSupport::TimeZone["EDT"]
=> nil

(These work for EST)

Looking at the TZInfo documentation, I found

A list of the unique offsets used by a time zone can be obtained with the offsets_up_to method. The result is returned as an Array of TZInfo::TimezoneOffset objects

So I tried

irb(main):013:0> TZInfo::Timezone.all.find { |tz| tz.offsets_up_to(Time.now).map(&:abbreviation).include?("EDT") }
=> #<TZInfo::TimezoneProxy: America/Cancun>

which is a wrong answer for me as Cancun used to have daylight savings time and so use EDT but doesn't any more.

Please note I am not asking about a time zone which is necessarily currently EDT, but which has EDT this year, at least.

CodePudding user response:

This is the best way I currently found: for each time zone use two dates one of which will have DST and another won't (if any date does), get offset abbreviations for them, and check if one of them is the same as my argument:

def tz_by_offset_abbr(abbr)
  year = Time.now.year
  dates = [Date.new(year, 1, 1), Date.new(year, 7, 1)]
  ActiveSupport::TimeZone.all.find do |tz|
    dates.any? { |date| date.in_time_zone(tz).zone == abbr }
  end
end

I get

irb(main):008:0> tz_by_offset_abbr("EDT")
=> #<ActiveSupport::TimeZone:0x000056501bd1ec48 @name="Eastern Time (US & Canada)", @utc_offset=nil, @tzinfo=#<TZInfo::DataTimezone: America/New_York>> 
irb(main):009:0> tz_by_offset_abbr("EST")
=> #<ActiveSupport::TimeZone:0x000056501bd1ec48 @name="Eastern Time (US & Canada)", @utc_offset=nil, @tzinfo=#<TZInfo::DataTimezone: America/New_York>>

CodePudding user response:

Generally speaking, one cannot affirmatively map abbreviations back to time zones - regardless of programming language. There are too many problems:

  • As you identified, the same abbreviation can be used by multiple different time zones, at different points in time.

  • Some time zone abbreviations may be used by multiple time zones at the same point in time - and those can be very different time zones. For example CST could be Central Standard Time, Cuba Standard Time, or China Standard Time. IST could be India Standard Time, Israel Standard Time, or Ireland Standard Time.

  • Some time zones may have more than one commonly used abbreviation, such as Hawaii using HST or HAST.

  • Some time zones may use different abbreviations depending on language of the person using them, such as Québec (Canada) using EST for English and HNE for French.

  • Some time zones don't have any abbreviation, whether in English or in another language. In such places, either the region/territory/country name is used, or just the offset from UTC.

So in general - Don't.

Alternatives include:

  • Persisting the IANA time zone identifier (ex: America/New_York) so you can always get back to the original time zone.

  • Persisting timestamps with their UTC offset (ex: 2022-12-31T00:00:00-05:00). While this doesn't tell you what time zone it is from, it does tell the offset in effect at that point in time for the originating time zone.

  • Use other context clues to hunt through lists of time zone abbreviations. For example, perhaps you are scraping a website with time information and see "3:00 CST". If you can infer that the site is in English, and you can infer that it is targeted at US readers, then its reasonable to infer that it means US Central Standard Time (America/Chicago). However, this doesn't work in all cases for all countries. Even for the US, you won't always be able to tell whether MST should map to America/Denver or America/Phoenix - unless you have yet more context clues.

  • Related