Class: Tilia::VObject::TimeZoneUtil

Inherits:
Object
  • Object
show all
Defined in:
lib/tilia/v_object/time_zone_util.rb

Overview

Time zone name translation.

This file translates well-known time zone names into “Olson database” time zone names.

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.mapObject

Returns the value of attribute map.



208
209
210
# File 'lib/tilia/v_object/time_zone_util.rb', line 208

def map
  @map
end

.microsoft_exchange_mapObject

Returns the value of attribute microsoft_exchange_map.



209
210
211
# File 'lib/tilia/v_object/time_zone_util.rb', line 209

def microsoft_exchange_map
  @microsoft_exchange_map
end

Class Method Details

.load_tz_mapsObject

This method will load in all the tz mapping information, if it’s not yet done.



197
198
199
200
201
202
203
204
205
# File 'lib/tilia/v_object/time_zone_util.rb', line 197

def self.load_tz_maps
  return @map if @map

  @map = TimeZoneData::PhpZones.list
  @map.merge!(TimeZoneData::ExchangeZones.list)
  @map.merge!(TimeZoneData::LotusZones.list)
  @map.merge!(TimeZoneData::WindowsZones.list)
  @map
end

.time_zone(tzid, vcalendar = nil, fail_if_uncertain = false) ⇒ ActiveSupport::TimeZone

This method will try to find out the correct timezone for an iCalendar date-time value.

You must pass the contents of the TZID parameter, as well as the full calendar.

If the lookup fails, this method will return the default PHP timezone (as configured using date_default_timezone_set, or the date.timezone ini setting).

Alternatively, if fail_if_uncertain is set to true, it will throw an exception if we cannot accurately determine the timezone.

Parameters:

  • tzid (String)
  • vcalendar (Component) (defaults to: nil)

Returns:

  • (ActiveSupport::TimeZone)


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/tilia/v_object/time_zone_util.rb', line 111

def self.time_zone(tzid, vcalendar = nil, fail_if_uncertain = false)
  # First we will just see if the tzid is a support timezone identifier.
  #
  # The only exception is if the timezone starts with (. This is to
  # handle cases where certain microsoft products generate timezone
  # identifiers that for instance look like:
  #
  # (GMT+01.00) Sarajevo/Warsaw/Zagreb
  #
  # Since PHP 5.5.10, the first bit will be used as the timezone and
  # this method will return just GMT+01:00. This is wrong, because it
  # doesn't take DST into account.

  unless tzid[0] == '('

    # PHP has a bug that logs PHP warnings even it shouldn't:
    # https://bugs.php.net/bug.php?id=67881
    #
    # That's why we're checking if we'll be able to successfull instantiate
    # \Date_time_zone before doing so. Otherwise we could simply instantiate
    # and catch the exception.
    return ActiveSupport::TimeZone.new(tzid) if ActiveSupport::TimeZone.new(tzid)
  end

  load_tz_maps

  # Next, we check if the tzid is somewhere in our tzid map.

  return ActiveSupport::TimeZone.new(@map[tzid]) if @map.key?(tzid)

  # Maybe the author was hyper-lazy and just included an offset. We
  # support it, but we aren't happy about it.
  matches = /^GMT(\+|-)([0-9]{4})$/.match(tzid)
  if matches

    # Note that the path in the source will never be taken from PHP 5.5.10
    # onwards. PHP 5.5.10 supports the "GMT+0100" style of format, so it
    # already gets returned early in this function. Once we drop support
    # for versions under PHP 5.5.10, this bit can be taken out of the
    # source.
    # @codeCoverageIgnoreStart
    return ActiveSupport::TimeZone.new("Etc/GMT#{matches[1]}#{matches[2][0..1].gsub(/^0+/, '')}")
    # @codeCoverageIgnoreEnd
  end

  if vcalendar
    # If that didn't work, we will scan VTIMEZONE objects
    vcalendar.select('VTIMEZONE').each do |vtimezone|
      next unless vtimezone['TZID'].to_s == tzid
      if vtimezone.key?('X-LIC-LOCATION')
        lic = vtimezone['X-LIC-LOCATION'].to_s

        # Libical generators may specify strings like
        # "SystemV/EST5EDT". For those we must remove the
        # SystemV part.
        lic = lic[8..-1] if lic[0...8] == 'SystemV/'

        return time_zone(lic, nil, fail_if_uncertain)
      end

      # Microsoft may add a magic number, which we also have an
      # answer for.
      next unless vtimezone.key?('X-MICROSOFT-CDO-TZID')
      cdo_id = vtimezone['X-MICROSOFT-CDO-TZID'].value.to_i

      # 2 can mean both Europe/Lisbon and Europe/Sarajevo.
      if cdo_id == 2 && vtimezone['TZID'].to_s.index('Sarajevo')
        return ActiveSupport::TimeZone.new('Europe/Sarajevo')
      end

      if @microsoft_exchange_map.key?(cdo_id)
        return ActiveSupport::TimeZone.new(@microsoft_exchange_map[cdo_id])
      end
    end
  end

  if fail_if_uncertain
    fail ArgumentError, "We were unable to determine the correct PHP timezone for tzid: #{tzid}"
  end

  # If we got all the way here, we default to UTC.
  Time.zone
end