Class: TZInfo::DataSource Abstract
Relationships & Source Files | |
Extension / Inclusion / Inheritance Descendants | |
Subclasses:
|
|
Inherits: | Object |
Defined in: | lib/tzinfo/data_source.rb |
Overview
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 .set method.
Class Method Summary
- .get ⇒ DataSource
-
.new ⇒ DataSource
constructor
Initializes a new
DataSource
instance. -
.set(data_source_or_type, *args)
Sets the currently selected data source for time zone and country data.
-
.create_default_data_source ⇒ DataSource
private
Creates a
DataSource
instance for use as the default.
Instance Method Summary
-
#country_codes ⇒ Array<String>
Returns a frozen
Array
of all the available ISO 3166-1 alpha-2 country codes. -
#data_timezone_identifiers ⇒ Array<String>
Returns a frozen
Array
of all the available time zone identifiers for data time zones (i.e. those that actually contain definitions). -
#eager_load!
Loads all timezone and country data into memory.
- #get_country_info(code) ⇒ DataSources::CountryInfo
-
#get_timezone_info(identifier) ⇒ DataSources::TimezoneInfo
Returns a
DataSources::TimezoneInfo
instance for the given identifier. - #inspect ⇒ String
-
#linked_timezone_identifiers ⇒ Array<String>
Returns a frozen
Array
of all the available time zone identifiers that are links to other time zones. - #timezone_identifiers ⇒ Array<String>
- #to_s ⇒ String
- #load_country_info(code) ⇒ DataSources::CountryInfo protected
-
#load_timezone_info(identifier) ⇒ DataSources::TimezoneInfo
protected
Returns a
DataSources::TimezoneInfo
instance for the given time zone identifier. -
#lookup_country_info(hash, code, encoding = Encoding::UTF_8) ⇒ DataSources::CountryInfo
protected
Looks up a given code in the given hash of code to
DataSources::CountryInfo
mappings. - #timezone_identifier_encoding ⇒ Encoding protected
-
#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
). -
#build_timezone_identifiers ⇒ Array<String>
private
Combines #data_timezone_identifiers and #linked_timezone_identifiers to create an
Array
containing all valid time zone identifiers. -
#find_timezone_identifier(identifier) ⇒ String
private
If the given
identifier
is contained within the #timezone_identifiersArray
, theString
instance representing that identifier from #timezone_identifiers is returned. -
#raise_invalid_data_source(method_name)
private
Raises
InvalidDataSource
to indicate that a method has not been overridden by a particular data source implementation. -
#try_with_encoding(string, encoding) {|s| ... } ⇒ Object
private
Tries an operation using
string
directly.
Constructor Details
.new ⇒ DataSource
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
Class Method Details
.create_default_data_source ⇒ DataSource
(private)
Creates a DataSource
instance for use as the default. Used if no
preference has been specified manually.
# File 'lib/tzinfo/data_source.rb', line 145
def create_default_data_source has_tzinfo_data = false begin require 'tzinfo/data' has_tzinfo_data = true rescue LoadError end return DataSources::RubyDataSource.new if has_tzinfo_data begin return DataSources::ZoneinfoDataSource.new rescue DataSources::ZoneinfoDirectoryNotFound raise DataSourceNotFound, "No source of timezone data could be found.\nPlease refer to https://tzinfo.github.io/datasourcenotfound for help resolving this error." end end
.get ⇒ DataSource
# 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)
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 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 .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
DataSources::ZoneinfoDataSource.search_path).
# 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
#build_timezone_identifiers ⇒ Array
<String
> (private)
Combines #data_timezone_identifiers and #linked_timezone_identifiers
to create an Array
containing all valid time zone identifiers. If
#linked_timezone_identifiers is empty, the #data_timezone_identifiers
instance is returned.
The returned Array
is frozen. The identifiers are sorted according to
String#<=>
.
# File 'lib/tzinfo/data_source.rb', line 366
def build_timezone_identifiers data = data_timezone_identifiers linked = linked_timezone_identifiers linked.empty? ? data : (data + linked).sort!.freeze end
#country_codes ⇒ Array
<String
>
Returns a frozen Array
of all the available ISO 3166-1 alpha-2 country
codes. The identifiers are sorted according to String#<=>
.
# File 'lib/tzinfo/data_source.rb', line 246
def country_codes raise_invalid_data_source('country_codes') end
#data_timezone_identifiers ⇒ Array
<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#<=>
.
# File 'lib/tzinfo/data_source.rb', line 218
def data_timezone_identifiers raise_invalid_data_source('data_timezone_identifiers') end
#eager_load!
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
#find_timezone_identifier(identifier) ⇒ String
(private)
If the given identifier
is contained within the #timezone_identifiers
Array
, the String
instance representing that identifier from
#timezone_identifiers is returned. Otherwise, nil
is returned.
:nocov_array_bsearch:
See additional method definition at line 382.
# File 'lib/tzinfo/data_source.rb', line 398
def find_timezone_identifier(identifier) result = timezone_identifiers.bsearch {|i| i >= identifier } result == identifier ? result : nil end
#get_country_info(code) ⇒ DataSources::CountryInfo
# 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 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.
# 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
#inspect ⇒ String
# File 'lib/tzinfo/data_source.rb', line 268
def inspect "#<#{self.class}>" end
#linked_timezone_identifiers ⇒ Array
<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#<=>
.
# 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)
# 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 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.
# 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
DataSources::CountryInfo
mappings. If the code is found the
DataSources::CountryInfo
is returned. Otherwise an InvalidCountryCode
exception is raised.
# 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
#raise_invalid_data_source(method_name) (private)
Raises InvalidDataSource
to indicate that a method has not been
overridden by a particular data source implementation.
# File 'lib/tzinfo/data_source.rb', line 352
def raise_invalid_data_source(method_name) raise InvalidDataSource, "#{method_name} not defined" end
#timezone_identifier_encoding ⇒ Encoding
(protected)
# File 'lib/tzinfo/data_source.rb', line 300
def timezone_identifier_encoding Encoding::UTF_8 end
#timezone_identifiers ⇒ Array
<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
#to_s ⇒ String
# File 'lib/tzinfo/data_source.rb', line 262
def to_s "Default DataSource" end
#try_with_encoding(string, encoding) {|s| ... } ⇒ Object
(private)
Tries an operation using string
directly. If the operation fails, the
string is copied and encoded with encoding
and the operation is tried
again.
fails and string
is already encoded with encoding
.
# File 'lib/tzinfo/data_source.rb', line 436
def try_with_encoding(string, encoding) result = yield string return result if result unless encoding == string.encoding string = string.encode(encoding) yield string end 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.
# 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