{"id":16575140,"url":"https://github.com/dmyersturnbull/suretime","last_synced_at":"2025-07-26T12:37:25.022Z","repository":{"id":37941021,"uuid":"331472157","full_name":"dmyersturnbull/suretime","owner":"dmyersturnbull","description":"Get IANA timezones and fully resolved timestamps, even on Windows.","archived":false,"fork":false,"pushed_at":"2023-08-07T03:43:38.000Z","size":143,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-19T08:46:44.165Z","etag":null,"topics":["cross-platform","iana","python","timezones","tzdata","windows"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dmyersturnbull.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null}},"created_at":"2021-01-21T00:44:12.000Z","updated_at":"2023-12-20T22:20:15.000Z","dependencies_parsed_at":"2022-08-11T10:50:21.895Z","dependency_job_id":null,"html_url":"https://github.com/dmyersturnbull/suretime","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/dmyersturnbull/suretime","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmyersturnbull%2Fsuretime","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmyersturnbull%2Fsuretime/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmyersturnbull%2Fsuretime/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmyersturnbull%2Fsuretime/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dmyersturnbull","download_url":"https://codeload.github.com/dmyersturnbull/suretime/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmyersturnbull%2Fsuretime/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266010447,"owners_count":23863580,"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":["cross-platform","iana","python","timezones","tzdata","windows"],"created_at":"2024-10-11T21:46:59.384Z","updated_at":"2025-07-26T12:37:24.987Z","avatar_url":"https://github.com/dmyersturnbull.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# suretime\n\n[![Version status](https://img.shields.io/pypi/status/suretime)](https://pypi.org/project/suretime)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Python version compatibility](https://img.shields.io/pypi/pyversions/suretime)](https://pypi.org/project/suretime)\n[![Version on GitHub](https://img.shields.io/github/v/release/dmyersturnbull/suretime?include_prereleases\u0026label=GitHub)](https://github.com/dmyersturnbull/suretime/releases)\n[![Version on PyPi](https://img.shields.io/pypi/v/suretime)](https://pypi.org/project/suretime)\n[![Build (GitHub Actions)](https://img.shields.io/github/workflow/status/dmyersturnbull/suretime/Build%20\u0026%20test?label=Build%20\u0026%20test)](https://github.com/dmyersturnbull/suretime/actions)\n[![Test coverage (coveralls)](https://coveralls.io/repos/github/dmyersturnbull/suretime/badge.svg?branch=main\u0026service=github)](https://coveralls.io/github/dmyersturnbull/suretime?branch=main)\n[![Maintainability (Code Climate)](https://api.codeclimate.com/v1/badges/14b23b28b0d9c37a0ebf/maintainability)](https://codeclimate.com/github/dmyersturnbull/suretime/maintainability)\n[![Code Quality (Scrutinizer)](https://scrutinizer-ci.com/g/dmyersturnbull/suretime/badges/quality-score.png?b=main)](https://scrutinizer-ci.com/g/dmyersturnbull/suretime/?branch=main)\n[![Created with Tyrannosaurus](https://img.shields.io/badge/Created_with-Tyrannosaurus-0000ff.svg)](https://github.com/dmyersturnbull/tyrannosaurus)\n\nMap nonstandard timezones to IANA zones on all platforms.\nRecord timestamps and intervals that behave correctly,\neven if the timezone changes in the middle of a calculation.\n`pip install suretime tzdata`.\n\n### Timezone mapping\n\nTo get the local zone in IANA:\n\n```python\nimport suretime\nfrom datetime import datetime\n\ndatetime.now().tzname()  # \"Pacific Standard Time\"\nsuretime.zone.first_local()  # ZoneInfo[America/Los_Angeles])\n```\n\nTo map a nonstandard zone from elsewhere:\n\n```python\nimport suretime\n\nsuretime.zone.only(\"Europe/Tiraspol\")  # ZoneInfo[Europe/Tiraspol]\nsuretime.zone.first(\"Central Pacific Standard Time\")  # ZoneInfo[Pacific/Guadalcanal]\nsuretime.zone.first(\n    \"Central Pacific Standard Time\", territory=\"AQ\"\n)  # ZoneInfo[Antarctica/Casey]\n```\n\nNote that there is no 1-1 mapping between Windows and IANA timezones,\nso suretime can fail despite its name.\n\n### \"Tagged\" datetimes and intervals\n\nsuretime also has models to represent timestamps and intervals as accurately as the system permits.\nFor example, a `TaggedInterval` contains the wall time, IANA zone, original (unmapped) timezone info\nfrom the system, monotonic (typically boottime) clock time, and the clock used.\n\nTimezone-resolved datetimes and intervals know both real and calendar times, correctly representing\nthe ground truth even if a timezone shift occurs between events – such as from a daylight savings change\nor the user boarding a flight.\n\n```python\nimport suretime\n\ntagged = suretime.tag.now()\ntagged.to_utc  # TaggedDateTime[...]\ntagged.clock.name  # \"boottime\" on most systems\ntagged == tagged  # same point in time\ntagged.iso_with_zone  # \"2021-01-20T22:24:13.219253-07:00 [America/Los_Angeles]\"\n```\n\n### Comparison to [tzlocal](https://github.com/regebro/tzlocal)\n\ntzlocal is a bit different. It:\n\n- ... only handles your current system’s timezone\n- ... is highly OS-specific\n- ... requires many system calls, making it typically _much_ slower\n- ... is compatible with Windows 2000, XP, and 7 and below\n- ... is compatible with Python 3.6, 3.7, and 3.8\n- ... very rarely, can access timezones on incorrectly configured POSIX systems\n\nYou can combine both packages, falling back to tzlocal if suretime fails.\n(See the example below).\n\n### Full example\n\n```python\nfrom datetime import datetime\nimport suretime\n\n# Get your local system, non-IANA timezone\nsystem_time = datetime.now().astimezone()\nsystem_timezone = system_time.tzname()  # e.g. Pacific Standard Time\n\n# Get an IANA timezone instead:\nsuretime.zone.only_local()  # ZoneInfo[America/Los_Angeles]\n# Or for an arbitrary system timezone name:\nsuretime.zone.first(system_timezone)  # ZoneInfo[America/Los_Angeles]\n# Of course, it maps IANA zones to themselves:\nsuretime.zone.only(\"America/Los_Angeles\")  # ZoneInfo[America/Los_Angeles]\n\n# Get all IANA timezones that could match a zone\n# The first uses the primary/null territory\n# The second uses the territory \"AQ\"\nsuretime.zone.all(\"Central Pacific Standard Time\")  # {ZoneInfo[Pacific/Guadalcanal]}\nsuretime.zone.all(\"Central Pacific Standard Time\", \"AQ\")  # {ZoneInfo[Antarctica/Casey]}\n\n# Get 1 matching IANA zone; \"get\" means optional\nsuretime.zone.first(\"Central Pacific Standard Time\", \"AQ\")  # ZoneInfo[Pacific/Casey]\nsuretime.zone.first(\"nonexistent zone\")  # None\nsuretime.zone.only(\"nonexistent zone\")  # errors\nsuretime.zone.only(\n    \"Central Pacific Standard Time\", \"any\"\n)  # fails (multiple possible IANA zones)\n\n# Get a fully resolved \"tagged datetime\"\n# It contains:\n# - The zoned datetime\n# - The primary IANA ZoneInfo\n# - The original system timezone\n# - A system wall time (`time.monotonic_ns`)\ntagged = suretime.tag.now_local_sys()  # TaggedDatetime[ ... ]\nprint(tagged.clock.name)  # e.g. \"boottime\"\n# or NTP:\ntagged = suretime.tag.now_local_ntp(\n    server=\"north-america\", kind=\"server-received\"\n)  # TaggedDatetime[ ... ]\n# or fully reliable but not keeping the local zone:\ntagged = suretime.tag.now_utc_ntp()  # TaggedDatetime[ ... ]\n# or NTP:\ntagged = suretime.tag.now_local_sys()  # TaggedDatetime[ ... ]\nprint(tagged.clock.name)  # \"ntp:...\"\nprint(tagged.clock.info.resolution)  # e.g. -7\n\n# 2021-01-20T22:24:13.219253-07:00 [America/Los_Angeles]\nprint(tagged.iso_with_zone)  # \u003cdatetime\u003e [zone]\nprint(tagged.source.territory)  # \"primary\"\n\n# if you only need the real time:\nsuretime.clock.sys()\n# or:\nsuretime.clock.ntp()\n# or for all of the NTP clock times:\nntp_data = suretime.clock.ntp_raw()\nprint(ntp_data.root_dispersion)\nprint(ntp_data.server_sent, ntp_data.client_received)\nprint(ntp_data.round_trip.total_seconds())\n\n# Adjust a tagged time to a new real time\ntagged = suretime.tag.now_utc_sys()  # TaggedDatetime[ ... ]\nsys_now = suretime.clock.sys()\ntagged.at(sys_now)\n# now the datetime is adjusted to where it should be at the new real time\n\n# Compare tagged datetimes\nprint(tagged \u003c tagged)  # False\nprint(tagged == tagged)  # True: They're the same point in time\nprint(tagged == system_time)  # True: They're the same point in time\nprint(tagged.is_identical_to(tagged))  # True: They're exactly the same\n\n# Get a \"tagged duration\" with the start and end, and monotonic real time in nanoseconds\nthen = suretime.tag.now()  # TaggedDatetime [ ... ]\nfor i in list(range(10000)):\n    i += 1  # Just waiting a little\nnow = suretime.tag.now()  # TaggedInterval [ ... ]\ninterval = suretime.tag.interval(then, now)  # TaggedInterval [ ... ]\nprint(interval.real_delta)  # Actual time passed\nprint(interval.wall_delta)  # Simple end - start\nprint(interval.iso)  # start--end in ISO 8601 format\nprint(interval.real_str)  # days:HH:mm:ss.millis.micros.nanos\nprint(interval.duration.iso)  # e.g. P0Y3M5DT14H22M35.223051S\n\n# use suretime, fall back to tzlocal\nimport tzlocal\n\n\ndef get_local() -\u003e suretime.Types.TaggedDatetime:\n    try:\n        return suretime.tag.now()\n    except suretime.Errors.CannotMapTzError:\n        zone = tzlocal.get_localzone()\n        return suretime.tag.exact(datetime.now(zone))\n```\n\n### 🍁 Contributing\n\nLicensed under the terms of the [Apache License 2.0](https://spdx.org/licenses/Apache-2.0.html).\n[New issues](https://github.com/dmyersturnbull/suretime/issues) and pull requests are welcome.\nPlease refer to the [contributing guide](https://github.com/dmyersturnbull/suretime/blob/main/CONTRIBUTING.md)\nand [security policy](https://github.com/dmyersturnbull/suretime/blob/main/SECURITY.md).\n\nGenerated with [Tyrannosaurus](https://github.com/dmyersturnbull/tyrannosaurus).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmyersturnbull%2Fsuretime","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdmyersturnbull%2Fsuretime","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmyersturnbull%2Fsuretime/lists"}