Class: TZInfo::DataSource Abstract

Inherits:
Object
  • Object
show all
Defined in:
lib/tzinfo/data_source.rb

Overview

This class is abstract.

To create a custom data source, create a subclass of DataSource and implement the #load_timezone_info, #data_timezone_identifiers, #linked_timezone_identifiers, #load_country_info and #country_codes methods.

TZInfo can be used with different data sources for time zone and country data. Each source of data is implemented as a subclass of DataSource.

To choose a data source and override the default selection, use the DataSource.set method.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeDataSource

Initializes a new TZInfo::DataSource instance. Typically only called via subclasses of TZInfo::DataSource.



166
167
168
# File 'lib/tzinfo/data_source.rb', line 166

def initialize
  @timezones = Concurrent::Map.new
end

Class Method Details

.getDataSource

Returns the currently selected source of data.

Returns:

  • (DataSource)

    the currently selected source of data.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/tzinfo/data_source.rb', line 42

def get
  # If a DataSource hasn't been manually set when the first request is
  # made to obtain a DataSource, then a default data source is created.
  #
  # This is done at the first request rather than when TZInfo is loaded to
  # avoid unnecessary attempts to find a suitable DataSource.
  #
  # A `Mutex` is used to ensure that only a single default instance is
  # created (this avoiding the possibility of retaining two copies of the
  # same data in memory).

  unless @@instance
    @@default_mutex.synchronize do
      set(create_default_data_source) unless @@instance
    end
  end

  @@instance
end

.set(data_source_or_type, *args) ⇒ Object

Sets the currently selected data source for time zone and country data.

This should usually be set to one of the two standard data source types:

  • :ruby - read data from the Ruby modules included in the TZInfo::Data library (tzinfo-data gem).
  • :zoneinfo - read data from the zoneinfo files included with most Unix-like operating systems (e.g. in /usr/share/zoneinfo).

To set TZInfo to use one of the standard data source types, call TZInfo::DataSource.set` in one of the following ways:

TZInfo::DataSource.set(:ruby)
TZInfo::DataSource.set(:zoneinfo)
TZInfo::DataSource.set(:zoneinfo, zoneinfo_dir)
TZInfo::DataSource.set(:zoneinfo, zoneinfo_dir, iso3166_tab_file)

DataSource.set(:zoneinfo) will automatically search for the zoneinfo directory by checking the paths specified in TZInfo::DataSources::ZoneinfoDataSource.search_path. TZInfo::DataSources::ZoneinfoDirectoryNotFound will be raised if no valid zoneinfo directory could be found.

DataSource.set(:zoneinfo, zoneinfo_dir) uses the specified zoneinfo_dir directory as the data source. If the directory is not a valid zoneinfo directory, a TZInfo::DataSources::InvalidZoneinfoDirectory exception will be raised.

DataSource.set(:zoneinfo, zoneinfo_dir, iso3166_tab_file) uses the specified zoneinfo_dir directory as the data source, but loads the iso3166.tab file from the path given by iso3166_tab_file. If the directory is not a valid zoneinfo directory, a TZInfo::DataSources::InvalidZoneinfoDirectory exception will be raised.

Custom data sources can be created by subclassing TZInfo::DataSource and implementing the following methods:

To have TZInfo use the custom data source, call set, passing an instance of the custom data source implementation as follows:

TZInfo::DataSource.set(CustomDataSource.new)

Calling set will only affect instances of Timezone and Country obtained with Timezone.get and Country.get subsequent to the set call. Existing Timezone and Country instances will be unaffected.

If set is not called, TZInfo will by default attempt to use TZInfo::Data as the data source. If TZInfo::Data is not available (i.e. if require 'tzinfo/data' fails), then TZInfo will search for a zoneinfo directory instead (using the search path specified by TZInfo::DataSources::ZoneinfoDataSource.search_path).

Parameters:

  • data_source_or_type (Object)

    either :ruby, :zoneinfo or an instance of a TZInfo::DataSource.

  • args (Array<Object>)

    when data_source_or_type is a symbol, optional arguments to use when initializing the data source.

Raises:

  • (ArgumentError)

    if data_source_or_type is not :ruby, :zoneinfo or an instance of TZInfo::DataSource.



127
128
129
130
131
132
133
134
135
136
137
# File 'lib/tzinfo/data_source.rb', line 127

def set(data_source_or_type, *args)
  if data_source_or_type.kind_of?(DataSource)
    @@instance = data_source_or_type
  elsif data_source_or_type == :ruby
    @@instance = DataSources::RubyDataSource.new
  elsif data_source_or_type == :zoneinfo
    @@instance = DataSources::ZoneinfoDataSource.new(*args)
  else
    raise ArgumentError, 'data_source_or_type must be a DataSource instance or a data source type (:ruby or :zoneinfo)'
  end
end

Instance Method Details

#country_codesArray<String>

Returns a frozen Array of all the available ISO 3166-1 alpha-2 country codes. The identifiers are sorted according to String#<=>.

Returns:

  • (Array<String>)

    a frozen Array of all the available ISO 3166-1 alpha-2 country codes.



246
247
248
# File 'lib/tzinfo/data_source.rb', line 246

def country_codes
  raise_invalid_data_source('country_codes')
end

#data_timezone_identifiersArray<String>

Returns a frozen Array of all the available time zone identifiers for data time zones (i.e. those that actually contain definitions). The identifiers are sorted according to String#<=>.

Returns:

  • (Array<String>)

    a frozen Array of all the available time zone identifiers for data time zones.



218
219
220
# File 'lib/tzinfo/data_source.rb', line 218

def data_timezone_identifiers
  raise_invalid_data_source('data_timezone_identifiers')
end

#eager_load!Object

Loads all timezone and country data into memory.

This may be desirable in production environments to improve copy-on-write performance and to avoid flushing the constant cache every time a new timezone or country is loaded from TZInfo::DataSources::RubyDataSource.



255
256
257
258
259
# File 'lib/tzinfo/data_source.rb', line 255

def eager_load!
  timezone_identifiers.each {|identifier| load_timezone_info(identifier) }
  country_codes.each {|code| load_country_info(code) }
  nil
end

#get_country_info(code) ⇒ DataSources::CountryInfo

Returns a TZInfo::DataSources::CountryInfo instance for the given ISO 3166-1 alpha-2 country code.

Parameters:

  • code (String)

    an ISO 3166-1 alpha-2 country code.

Returns:

Raises:



237
238
239
# File 'lib/tzinfo/data_source.rb', line 237

def get_country_info(code)
  load_country_info(code)
end

#get_timezone_info(identifier) ⇒ DataSources::TimezoneInfo

Returns a TZInfo::DataSources::TimezoneInfo instance for the given identifier. The result will derive from either TZInfo::DataSources::DataTimezoneInfo for time zones that define their own data or TZInfo::DataSources::LinkedTimezoneInfo for links or aliases to other time zones.

#get_timezone_info calls #load_timezone_info to create the TZInfo::DataSources::TimezoneInfo instance. The returned instance is cached and returned in subsequent calls to #get_timezone_info for the identifier.

Parameters:

  • identifier (String)

    A time zone identifier.

Returns:

Raises:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/tzinfo/data_source.rb', line 184

def get_timezone_info(identifier)
  result = @timezones[identifier]

  unless result
    # Thread-safety: It is possible that multiple equivalent TimezoneInfo
    # instances could be created here in concurrently executing threads. The
    # consequences of this are that the data may be loaded more than once
    # (depending on the data source). The performance benefit of ensuring
    # that only a single instance is created is unlikely to be worth the
    # overhead of only allowing one TimezoneInfo to be loaded at a time.

    result = load_timezone_info(identifier)
    @timezones[result.identifier] = result
  end

  result
end

#inspectString

Returns the internal object state as a programmer-readable String.

Returns:

  • (String)

    the internal object state as a programmer-readable String.



268
269
270
# File 'lib/tzinfo/data_source.rb', line 268

def inspect
  "#<#{self.class}>"
end

#linked_timezone_identifiersArray<String>

Returns a frozen Array of all the available time zone identifiers that are links to other time zones. The identifiers are sorted according to String#<=>.

Returns:

  • (Array<String>)

    a frozen Array of all the available time zone identifiers that are links to other time zones.



228
229
230
# File 'lib/tzinfo/data_source.rb', line 228

def linked_timezone_identifiers
  raise_invalid_data_source('linked_timezone_identifiers')
end

#load_country_info(code) ⇒ DataSources::CountryInfo (protected)

Returns a TZInfo::DataSources::CountryInfo instance for the given ISO 3166-1 alpha-2 country code.

Parameters:

  • code (String)

    an ISO 3166-1 alpha-2 country code.

Returns:

Raises:



294
295
296
# File 'lib/tzinfo/data_source.rb', line 294

def load_country_info(code)
  raise_invalid_data_source('load_country_info')
end

#load_timezone_info(identifier) ⇒ DataSources::TimezoneInfo (protected)

Returns a TZInfo::DataSources::TimezoneInfo instance for the given time zone identifier. The result should derive from either TZInfo::DataSources::DataTimezoneInfo for time zones that define their own data or TZInfo::DataSources::LinkedTimezoneInfo for links to or aliases for other time zones.

Parameters:

  • identifier (String)

    A time zone identifier.

Returns:

Raises:



285
286
287
# File 'lib/tzinfo/data_source.rb', line 285

def load_timezone_info(identifier)
  raise_invalid_data_source('load_timezone_info')
end

#lookup_country_info(hash, code, encoding = Encoding::UTF_8) ⇒ DataSources::CountryInfo (protected)

Looks up a given code in the given hash of code to TZInfo::DataSources::CountryInfo mappings. If the code is found the TZInfo::DataSources::CountryInfo is returned. Otherwise an InvalidCountryCode exception is raised.

Parameters:

  • hash (String, DataSources::CountryInfo)

    a mapping from ISO 3166-1 alpha-2 country codes to TZInfo::DataSources::CountryInfo instances.

  • code (String)

    a country code to lookup.

  • encoding (Encoding) (defaults to: Encoding::UTF_8)

    the encoding used for the country codes in hash.

Returns:

Raises:



337
338
339
340
341
342
343
344
# File 'lib/tzinfo/data_source.rb', line 337

def lookup_country_info(hash, code, encoding = Encoding::UTF_8)
  raise InvalidCountryCode, "Invalid country code: #{code.nil? ? 'nil' : code}" unless code.kind_of?(String)

  info = try_with_encoding(code, encoding) {|c| hash[c] }
  return info if info

  raise InvalidCountryCode, "Invalid country code: #{code.encode(Encoding::UTF_8)}"
end

#timezone_identifier_encodingEncoding (protected)

Returns the Encoding used by the String instances returned by #data_timezone_identifiers and #linked_timezone_identifiers.

Returns:



300
301
302
# File 'lib/tzinfo/data_source.rb', line 300

def timezone_identifier_encoding
  Encoding::UTF_8
end

#timezone_identifiersArray<String>

Returns a frozen Arrayof all the available time zone identifiers. The identifiers are sorted according toString#<=>`.

Returns:

  • (Array<String>)

    a frozen Arrayof all the available time zone identifiers. The identifiers are sorted according toString#<=>`.



204
205
206
207
208
209
210
# File 'lib/tzinfo/data_source.rb', line 204

def timezone_identifiers
  # Thread-safety: It is possible that the value of @timezone_identifiers
  # may be calculated multiple times in concurrently executing threads. It
  # is not worth the overhead of locking to ensure that
  # @timezone_identifiers is only calculated once.
  @timezone_identifiers ||= build_timezone_identifiers
end

#to_sString

Returns a description of the TZInfo::DataSource.

Returns:



262
263
264
# File 'lib/tzinfo/data_source.rb', line 262

def to_s
  "Default DataSource"
end

#validate_timezone_identifier(identifier) ⇒ String (protected)

Checks that the given identifier is a valid time zone identifier (can be found in the #timezone_identifiers Array). If the identifier is valid, the String instance representing that identifier from timezone_identifiers is returned. Otherwise an InvalidTimezoneIdentifier exception is raised.

Parameters:

  • identifier (String)

    a time zone identifier to be validated.

Returns:

Raises:



315
316
317
318
319
320
321
322
# File 'lib/tzinfo/data_source.rb', line 315

def validate_timezone_identifier(identifier)
  raise InvalidTimezoneIdentifier, "Invalid identifier: #{identifier.nil? ? 'nil' : identifier}" unless identifier.kind_of?(String)

  valid_identifier = try_with_encoding(identifier, timezone_identifier_encoding) {|id| find_timezone_identifier(id) }
  return valid_identifier if valid_identifier

  raise InvalidTimezoneIdentifier, "Invalid identifier: #{identifier.encode(Encoding::UTF_8)}"
end