New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to add LinkedTimezoneInfo to a DataSource #72

Closed
ggrochow opened this Issue Sep 22, 2017 · 2 comments

Comments

Projects
None yet
2 participants
@ggrochow

ggrochow commented Sep 22, 2017

I have some an existing application, that uses some non-standard time-zone mappings, When trying to setup a rails API, I ran into some issues, saying they weren't valid timezones.

I would like to add some aliases to a few timezones, which appears to be do-able with the LinkedTimezoneInfo class, however, Im getting a little stumped on how to actually include these additional timezones in the data.

Its looking like I have to sub-class and fully implement my own data-source loading, Is this correct?

Is there an easy way to use an existing data-source loading method, and just add a few extra things to the data-source?

TL:DR;
I want to be able to use 'GMT-07:00' which isn't a valid timezone identifier, and have it link to the existing, valid 'Etc/Gmt-7' TZ. How do I get TzInfo::Timezone.get('GMT-07:00') to return the TZ i want, instead of an 'TZ not found' exception

@philr

This comment has been minimized.

Show comment
Hide comment
@philr

philr Sep 23, 2017

Member

You can create a custom DataSource class that extends one of the built-in data source implementations. This class can handle requests for custom aliases, deferring any other request to the built-in implementation.

You'll need to decide which of the built-in DataSource implementations to extend: RubyDataSource if you want to use the tzinfo-data gem as the source of time zone data, or ZoneinfoDataSource if you want to use the system zoneinfo files. You can run TZInfo::DataSource.get to see which one you're using at the moment.

Your custom DataSource class would need to look something like this:

class CustomDataSource < TZInfo::ZoneinfoDataSource # or TZInfo::RubyDataSource
  def initialize
    super
    @aliases = {
      'GMT-07:00' => 'Etc/GMT-7'
      # ...
    }
  end

  def load_timezone_info(identifier)
    if @aliases.include?(identifier)
      TZInfo::LinkedTimezoneInfo.new(identifier, @aliases[identifier])
    else
      super(identifier)
    end
  end

  def timezone_identifiers
    @timezone_identifiers_with_aliases ||= (super + @aliases.keys).sort.freeze
  end

  def linked_timezone_identifiers
    @linked_timezone_identifiers_with_aliases ||= (super + @aliases.keys).sort.freeze
  end
end

The CustomDataSource class will need to be selected before TZInfo is first used:

TZInfo::DataSource.set(CustomDataSource.new)

Once set, you'll be able to get zones using the custom aliases:

> tz = TZInfo::Timezone.get('GMT-07:00')
=> #<TZInfo::LinkedTimezone: GMT-07:00>
> tz.canonical_identifier
=> "Etc/GMT-7"

Note that the Etc/GMT+-n zones are backwards from what most people expect (see #69). You might want GMT-07:00 to map to Etc/GMT+7 instead.

The above code will work with TZInfo version 1.2.x. Some minor changes will be needed to work with the next major release of TZInfo, which will move the RubyDataSource, ZoneinfoDataSource and LinkedTimezoneInfo classes from the TZInfo namespace to TZInfo::DataSources.

Member

philr commented Sep 23, 2017

You can create a custom DataSource class that extends one of the built-in data source implementations. This class can handle requests for custom aliases, deferring any other request to the built-in implementation.

You'll need to decide which of the built-in DataSource implementations to extend: RubyDataSource if you want to use the tzinfo-data gem as the source of time zone data, or ZoneinfoDataSource if you want to use the system zoneinfo files. You can run TZInfo::DataSource.get to see which one you're using at the moment.

Your custom DataSource class would need to look something like this:

class CustomDataSource < TZInfo::ZoneinfoDataSource # or TZInfo::RubyDataSource
  def initialize
    super
    @aliases = {
      'GMT-07:00' => 'Etc/GMT-7'
      # ...
    }
  end

  def load_timezone_info(identifier)
    if @aliases.include?(identifier)
      TZInfo::LinkedTimezoneInfo.new(identifier, @aliases[identifier])
    else
      super(identifier)
    end
  end

  def timezone_identifiers
    @timezone_identifiers_with_aliases ||= (super + @aliases.keys).sort.freeze
  end

  def linked_timezone_identifiers
    @linked_timezone_identifiers_with_aliases ||= (super + @aliases.keys).sort.freeze
  end
end

The CustomDataSource class will need to be selected before TZInfo is first used:

TZInfo::DataSource.set(CustomDataSource.new)

Once set, you'll be able to get zones using the custom aliases:

> tz = TZInfo::Timezone.get('GMT-07:00')
=> #<TZInfo::LinkedTimezone: GMT-07:00>
> tz.canonical_identifier
=> "Etc/GMT-7"

Note that the Etc/GMT+-n zones are backwards from what most people expect (see #69). You might want GMT-07:00 to map to Etc/GMT+7 instead.

The above code will work with TZInfo version 1.2.x. Some minor changes will be needed to work with the next major release of TZInfo, which will move the RubyDataSource, ZoneinfoDataSource and LinkedTimezoneInfo classes from the TZInfo namespace to TZInfo::DataSources.

@ggrochow

This comment has been minimized.

Show comment
Hide comment
@ggrochow

ggrochow Sep 23, 2017

Thanks so much for the quick and detailed reply, ( including
including the gotcha that I 100% would have fallen for and probably not noticed immediately ).

Got this sorted fairly quickly, stuck this in a rails initializer and things are working as expected.

ggrochow commented Sep 23, 2017

Thanks so much for the quick and detailed reply, ( including
including the gotcha that I 100% would have fallen for and probably not noticed immediately ).

Got this sorted fairly quickly, stuck this in a rails initializer and things are working as expected.

@philr philr closed this Sep 23, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment