class TZInfo::DataSource
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.
@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.
Public Class Methods
@return [DataSource] the currently selected source of data.
# 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
Initializes a new {DataSource} instance. Typically only called via subclasses of {DataSource}.
# File lib/tzinfo/data_source.rb, line 166 def initialize @timezones = Concurrent::Map.new end
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 {DataSources::ZoneinfoDataSource.search_path}. {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 {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 {DataSources::InvalidZoneinfoDirectory} exception will be raised.
Custom data sources can be created by subclassing TZInfo::DataSource
and implementing the following methods:
-
{load_timezone_info}
-
{data_timezone_identifiers}
-
{linked_timezone_identifiers}
-
{load_country_info}
-
{country_codes}
To have TZInfo
use the custom data source, call {DataSource.set}, passing an instance of the custom data source implementation as follows:
TZInfo::DataSource.set(CustomDataSource.new)
Calling {DataSource.set} will only affect instances of {Timezone} and {Country} obtained with {Timezone.get} and {Country.get} subsequent to the {DataSource.set} call. Existing {Timezone} and {Country} instances will be unaffected.
If {DataSource.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 {DataSources::ZoneinfoDataSource.search_path}).
@param data_source_or_type [Object] either ‘:ruby`, `:zoneinfo` or an
instance of a {DataSource}.
@param args [Array<Object>] when ‘data_source_or_type` is a symbol,
optional arguments to use when initializing the data source.
@raise [ArgumentError] if ‘data_source_or_type` is not `:ruby`,
`:zoneinfo` or an instance of {DataSource}.
# 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
Public Instance Methods
Returns a frozen ‘Array` of all the available ISO 3166-1 alpha-2 country codes. The identifiers are sorted according to `String#<=>`.
@return [Array<String>] a frozen ‘Array` of all the available ISO 3166-1
alpha-2 country codes.
# File lib/tzinfo/data_source.rb, line 246 def country_codes raise_invalid_data_source('country_codes') end
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#<=>`.
@return [Array<String>] a frozen ‘Array` of all the available time zone
identifiers for data time zones.
# File lib/tzinfo/data_source.rb, line 218 def data_timezone_identifiers raise_invalid_data_source('data_timezone_identifiers') end
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 {DataSources::RubyDataSource}.
# 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
@param code [String] an ISO 3166-1 alpha-2 country code. @return [DataSources::CountryInfo] a {DataSources::CountryInfo} instance
for the given ISO 3166-1 alpha-2 country code.
@raise [InvalidCountryCode] if the country could not be found or the code
is invalid.
# File lib/tzinfo/data_source.rb, line 237 def get_country_info(code) load_country_info(code) end
Returns a {DataSources::TimezoneInfo} instance for the given identifier. The result will derive from either {DataSources::DataTimezoneInfo} for time zones that define their own data or {DataSources::LinkedTimezoneInfo} for links or aliases to other time zones.
{get_timezone_info} calls {load_timezone_info} to create the {DataSources::TimezoneInfo} instance. The returned instance is cached and returned in subsequent calls to {get_timezone_info} for the identifier.
@param identifier [String] A time zone identifier. @return [DataSources::TimezoneInfo] a {DataSources::TimezoneInfo} instance
for a given identifier.
@raise [InvalidTimezoneIdentifier] if the time zone is not found or the
identifier is invalid.
# 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
@return [String] the internal object state as a programmer-readable
`String`.
# File lib/tzinfo/data_source.rb, line 268 def inspect "#<#{self.class}>" end
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#<=>`.
@return [Array<String>] a frozen ‘Array` of all the available time zone
identifiers that are links to other time zones.
# File lib/tzinfo/data_source.rb, line 228 def linked_timezone_identifiers raise_invalid_data_source('linked_timezone_identifiers') end
@return [Array<String>] a frozen ‘Array“ of all the available time zone
identifiers. The identifiers are sorted according to `String#<=>`.
# 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
@return [String] a description of the {DataSource}.
# File lib/tzinfo/data_source.rb, line 262 def to_s "Default DataSource" end
Protected Instance Methods
@param code [String] an ISO 3166-1 alpha-2 country code. @return [DataSources::CountryInfo] a {DataSources::CountryInfo} instance
for the given ISO 3166-1 alpha-2 country code.
@raise [InvalidCountryCode] if the country could not be found or the code
is invalid.
# File lib/tzinfo/data_source.rb, line 294 def load_country_info(code) raise_invalid_data_source('load_country_info') end
Returns a {DataSources::TimezoneInfo} instance for the given time zone identifier. The result should derive from either {DataSources::DataTimezoneInfo} for time zones that define their own data or {DataSources::LinkedTimezoneInfo} for links to or aliases for other time zones.
@param identifier [String] A time zone identifier. @return [DataSources::TimezoneInfo] a {DataSources::TimezoneInfo} instance
for the given time zone identifier.
@raise [InvalidTimezoneIdentifier] if the time zone is not found or the
identifier is invalid.
# File lib/tzinfo/data_source.rb, line 285 def load_timezone_info(identifier) raise_invalid_data_source('load_timezone_info') end
Looks up a given code in the given hash of code to {DataSources::CountryInfo} mappings. If the code is found the {DataSources::CountryInfo} is returned. Otherwise an {InvalidCountryCode} exception is raised.
@param hash [String, DataSources::CountryInfo
] a mapping from ISO 3166-1
alpha-2 country codes to {DataSources::CountryInfo} instances.
@param code [String] a country code to lookup. @param encoding [Encoding] the encoding used for the country codes in
`hash`.
@return [DataSources::CountryInfo] the {DataSources::CountryInfo} instance
corresponding to `code`.
@raise [InvalidCountryCode] if ‘code` was not found in `hash`.
# 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
@return [Encoding] the ‘Encoding` used by the `String` instances returned
by {data_timezone_identifiers} and {linked_timezone_identifiers}.
# File lib/tzinfo/data_source.rb, line 300 def timezone_identifier_encoding Encoding::UTF_8 end
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.
@param identifier [String] a time zone identifier to be validated. @return [String] the ‘String` instance equivalent to `identifier` from
{timezone_identifiers}.
@raise [InvalidTimezoneIdentifier] if ‘identifier` was not found in
{timezone_identifiers}.
# 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