{"id":13483830,"url":"https://github.com/panthomakos/timezone","last_synced_at":"2025-05-14T07:09:06.930Z","repository":{"id":427051,"uuid":"1358009","full_name":"panthomakos/timezone","owner":"panthomakos","description":"Accurate current and historical timezones for Ruby with support for Geonames and Google latitude - longitude lookups.","archived":false,"fork":false,"pushed_at":"2025-03-23T00:17:08.000Z","size":1346,"stargazers_count":358,"open_issues_count":4,"forks_count":49,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-10T14:02:32.048Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://rubygems.org/gems/timezone","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/panthomakos.png","metadata":{"files":{"readme":"README.markdown","changelog":"CHANGES.markdown","contributing":"CONTRIBUTING.markdown","funding":null,"license":"License.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2011-02-12T07:39:56.000Z","updated_at":"2025-04-23T02:05:44.000Z","dependencies_parsed_at":"2024-06-18T13:50:55.128Z","dependency_job_id":"8e5dc15f-9f4e-4bc9-923e-a94c36e3ecd7","html_url":"https://github.com/panthomakos/timezone","commit_stats":{"total_commits":304,"total_committers":23,"mean_commits":"13.217391304347826","dds":"0.19736842105263153","last_synced_commit":"466645c7dd694681c8a37da25dc5c6256922f776"},"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panthomakos%2Ftimezone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panthomakos%2Ftimezone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panthomakos%2Ftimezone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panthomakos%2Ftimezone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/panthomakos","download_url":"https://codeload.github.com/panthomakos/timezone/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254092776,"owners_count":22013290,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T17:01:15.727Z","updated_at":"2025-05-14T07:09:01.919Z","avatar_url":"https://github.com/panthomakos.png","language":"Ruby","readme":"# Timezone\n![ci](https://github.com/panthomakos/timezone/actions/workflows/ci.yml/badge.svg)\n[![maintainability](https://api.codeclimate.com/v1/badges/d19a4a37dcbd373ac566/maintainability)](https://codeclimate.com/github/panthomakos/timezone/maintainability)\n\nAccurate current and history timezones for Ruby.\n\n* Uses [IANA Timezone Database][tz-database] for up-to-date historical timezone calculations.\n* Uses the [Geonames API][geonames-api] or the [Google Timezone API][google-api] for timezone latitude and longitude lookup.\n\n[tz-database]: https://www.iana.org/time-zones\n[geonames-api]: http://www.geonames.org/export/web-services.html\n[google-api]: https://developers.google.com/maps/documentation/timezone/\n\n## Installation\n\nUse the [`timezone`](https://rubygems.org/gems/timezone) gem - available on RubyGems. Semantic versioning is used, so if you would like to remain up-to-date and avoid any backwards-incompatible changes, use the following in your `Gemfile`:\n\n    gem 'timezone', '~\u003e 1.0'\n\n## RubyDocs\n\nComplete documentation for this gem can be found on [RubyDoc](http://www.rubydoc.info/gems/timezone).\n\n## Simple Timezone Queries\n\nSimple querying of time, in any timezone, is accomplished by first retrieving a `Timezone::Zone` object and then calling methods on that object.\n\n    timezone = Timezone['America/Los_Angeles']\n    =\u003e #\u003cTimezone::Zone name: \"America/Los_Angeles\"\u003e\n\n    timezone.valid?\n    =\u003e true\n\n    timezone.utc_to_local(Time.now)\n    =\u003e 2011-02-11 17:29:05 UTC\n\n    timezone.utc_to_local(Time.utc(2010, 1, 1, 0, 0, 0))\n    =\u003e 2009-12-31 16:00:00 UTC\n\n    timezone.time_with_offset(Time.utc(2010, 1, 1, 0, 0, 0))\n    =\u003e 2009-12-31 16:00:00 -0800\n\n    timezone.abbr(Time.new(2016, 9, 4, 1, 0, 0))\n    =\u003e \"PDT\"\n\nNOTE: time is always returned in the UTC timezone when using the `utc_to_local` function, but it accurately reflects the actual time in the specified timezone. The reason for this is that this function also takes into account daylight savings time and historical changes in timezone, which can alter the offset. If you want a time with the appropriate offset at the given time, then use the `time_with_offset` function as shown above.\n\nYou can use the timezone object to convert local times into the best UTC\nestimate. The reason this is an estimate is that some local times do not\nactually map to UTC times (for example when time jumps forward) and some\nlocal times map to multiple UTC times (for example when time falls back).\n\n    timezone = Timezone.fetch('America/Los_Angeles')\n    =\u003e #\u003cTimezone::Zone name: \"America/Los_Angeles\"\u003e\n\n    timezone.local_to_utc(Time.utc(2015,11,1,1,50,0))\n    =\u003e 2015-11-01 08:50:00 UTC\n\nYou can also query a `Timezone::Zone` object to determine if it was in Daylight\nSavings Time.\n\n    timezone = Timezone['America/Los_Angeles']\n    =\u003e #\u003cTimezone::Zone name: \"America/Los_Angeles\"\u003e\n\n    timezone.dst?(Time.now)\n    =\u003e true\n\n    timezone.dst?(Time.utc(2010, 1, 1, 0, 0, 0))\n    =\u003e false\n\nFor more information on the `::Timezone::Zone` object, see the [RubyDocs](http://www.rubydoc.info/gems/timezone/Timezone/Zone).\n\n## Finding Timezones Based on Latitude and Longitude\n\n`timezone` has the capacity to query Geonames and Google for timezones based on latitude and longitude. Before querying a timezone API you'll need to configure the API you want to use.\n\n### Lookup Configuration with Geonames\n\n1. Ensure you have a Geonames username. It's free and easy to setup, you can do so [here](http://www.geonames.org/login).\n1. Ensure you have enabled web services [here](http://www.geonames.org/enablefreewebservice).\n1. Configure your lookup. NOTE: in Rails it is recommended that you add this code to an initializer.\n\n        Timezone::Lookup.config(:geonames) do |c|\n          c.username = 'your_geonames_username_goes_here'\n        end\n\n### Lookup Configuration with Google\n\n1. Ensure you have a Google API Key, which you can get [here](https://code.google.com/apis/console/).\n1. Enable the Google Maps Time Zone API.\n1. Configure your lookup. NOTE: in Rails it is recommended that you add this code to an initializer.\n\n        Timezone::Lookup.config(:google) do |c|\n          c.api_key = 'your_google_api_key_goes_here'\n          c.client_id = 'your_google_client_id' # if using 'Google for Work'\n        end\n\n### Performing Latitude - Longitude Lookups\n\nAfter configuring the API of your choice, pass the lookup coordinates to `Timezone::lookup`.\n\n    timezone = Timezone.lookup(-34.92771808058, 138.477041423321)\n    =\u003e #\u003cTimezone::Zone name: \"Australia/Adelaide\"\u003e\n\n    timezone.name\n    =\u003e \"Australia/Adelaide\"\n\n    timezone.utc_to_local(Time.now)\n    =\u003e 2011-02-12 12:02:13 UTC\n\n### Latitude - Longitude Lookups for [Etcetera](https://www.ietf.org/timezones/data/etcetera) areas\n\nBy default both Geonames and Google do not provide results for lookups outside of continents and country borders. For example, if you try coordinates `[0, 0]` (somewhere in the Atlantic Ocean), you will get an exception.\n\nBut there is a way to get lookups for the whole Earth surface working (with Geonames only). Just add the `offset_etc_areas` option to the lookup configuration:\n\n        Timezone::Lookup.config(:geonames) do |c|\n          c.username = 'your_geonames_username_goes_here'\n          c.offset_etc_zones = true\n        end\n\nThen try to lookup coordinates in Etc area:\n\n    timezone = Timezone.lookup(89, 40)\n    =\u003e #\u003cTimezone::Zone name: \"Etc/GMT-3\"\u003e\n\n    timezone.name\n    =\u003e \"Etc/GMT-3\"\n\n    timezone.utc_offset\n    =\u003e 10800\n\nNOTE: `Etc/GMT` zones have POSIX-style signs in their names, with positive signs west of Greenwich. For example, \"Etc/GMT-3\" zone has a negative sign, but a positive UTC offset (10800 seconds or +3 hours) and its time is ahead of UTC (east of Greenwich) by 3 hours.\n\n## Error States and Nil Objects\n\nAll exceptions raised by the `timezone` gem are subclasses of `::Timezone::Error::Base`. `timezone` also provides a default `nil` timezone object that behaves like a `Timezone::Zone` except that it is invalid.\n\n    Timezone.fetch('foobar')\n    =\u003e Timezone::Error::InvalidZone\n\n    Timezone::Error::InvalidZone \u003c Timezone::Error::Base\n    =\u003e true\n\n    Timezone.fetch('foobar', Timezone['America/Los_Angeles'])\n    =\u003e #\u003cTimezone::Zone name: \"America/Los_Angeles\"\u003e\n\n    Timezone.fetch('foobar'){ |name| \"#{name} is invalid\" }\n    =\u003e \"foobar is invalid\"\n\n    zone = Timezone['foo/bar']\n    =\u003e #\u003cTimezone::NilZone\u003e\n\n    zone.valid?\n    =\u003e false\n\nFor more information on errors, check [`::Timezone::Error`](http://www.rubydoc.info/gems/timezone/Timezone/Error).\n\nFor more information on the `nil` object, check [`::Timezone::NilZone`](http://www.rubydoc.info/gems/timezone/Timezone/NilZone).\n\nLatitude - longitude lookups can raise `::Timezone::Error::Lookup` exceptions when issues occur with the remote API request. For example, if an API limit is reached. If the request is valid but the result does not return a valid timezone, then an `::Timezone::Error::InvalidZone` exception will be raised, or a default value will be returned if you have provided one.\n\n    Timezone.lookup(10, 10)\n    =\u003e Timezone::Error::Geonames: api limit reached\n\n    Timezone.lookup(10, 100000)\n    =\u003e Timezone::Error::InvalidZone\n\n    Timezone.lookup(10, 100000, Timezone::NilZone.new)\n    =\u003e #\u003cTimezone::NilZone\u003e\n\n    Timezone.lookup(10, 100000){ |name| \"#{name} is invalid\" }\n    =\u003e \" is invalid\"\n\n## Using Geonames and Google Lookups\n\n`timezone` can be configured to use both Google and Geonames lookups. For instance, you may choose to fallback to Google if a Geonames lookup fails. The return value from a `::Timezone::Lookup.config` call can be stored and re-used to trigger lookups for the configured service. For instance:\n\n    GEONAMES_LOOKUP = Timezone::Lookup.config(:geonames) { |c| c.username = ... }\n    GOOGLE_LOOKUP = Timezone::Lookup.config(:google) { |c| c.api_key = ... }\n\n    lat, lon = 89, 40\n\n    begin\n      GEONAMES_LOOKUP.lookup(lat, lon)\n    rescue ::Timezone::Error::Lookup\n      GOOGLE_LOOKUP.lookup(lat, lon)\n    end\n\n## Listing Timezones\n\nRetrieving the complete list of timezones can be accomplished using the `::Timezone::names` function. NOTE: the list is not ordered.\n\n    Timezone.names\n    =\u003e [\"EST\", \"Indian/Comoro\", \"Indian/Christmas\", \"Indian/Cocos\", ...]\n\n\n## Using Your Own HTTP Request Handler\n\nIf you have non-standard http request needs or want to have more control over API calls to Geonames and Google, you can write your own http request handler instead of using the built-in client.\n\nHere is a sample request handler that uses `open-uri` to perform requests.\n\n    require 'open-uri'\n\n    class MyRequestHandler\n      def initialize(config)\n        @protocol = config.protocol\n        @url = config.url\n      end\n\n      Response = Struct.new(:body, :code)\n\n      # Return a response object that responds to #body and #code\n      def get(path)\n        response = open(\"#{@protocol}://#{@url}#{path}\")\n\n        Response.new(response.read, response.status.first)\n      rescue OpenURI::HTTPError\n        Response.new(nil, '500')\n      end\n    end\n\nThis custom request handler can be configured for Google or Geonames. For example, to configure with Geonames you would do the following:\n\n    Timezone::Lookup.config(:geonames) do |c|\n      c.username = 'foobar'\n      c.request_handler = MyRequestHandler\n    end\n\n## Testing Timezone Lookups\n\nYou can provide your own lookup stubs using the built in `::Timezone::Lookup::Test` class.\n\n    ::Timezone::Lookup.config(:test)\n    =\u003e #\u003cTimezone::Lookup::Test:... @stubs={}\u003e\n\n    ::Timezone::Lookup.lookup.stub(-10, 10, 'America/Los_Angeles')\n    =\u003e \"America/Los_Angeles\"\n\n    ::Timezone.lookup(-10, 10).name\n    =\u003e 'America/Los_Angeles'\n\n    ::Timezone.lookup(-11, 11)\n    =\u003e Timezone::Error::Test: missing stub\n    \nYou can also provide a fallback lookup, which will be returned if you query an un-stubbed lookup value.\n\n    ::Timezone::Lookup.lookup.default('America/Los_Angeles')\n    =\u003e \"America/Los_Angeles\"\n","funding_links":[],"categories":["Ruby","Date and Time Processing"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpanthomakos%2Ftimezone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpanthomakos%2Ftimezone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpanthomakos%2Ftimezone/lists"}