{"id":44708345,"url":"https://github.com/ikelaiah/tzbundler","last_synced_at":"2026-02-15T11:14:00.740Z","repository":{"id":306901653,"uuid":"1026693154","full_name":"ikelaiah/tzbundler","owner":"ikelaiah","description":"🌍 Parse IANA timezone database into JSON \u0026 SQLite with Windows timezone support. Includes DST rules, historical transitions, and comprehensive metadata for timezone-aware applications.","archived":false,"fork":false,"pushed_at":"2025-07-28T09:34:18.000Z","size":5166,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-28T11:15:13.257Z","etag":null,"topics":["bundler","cldr","daylight-saving","dst","iana","json","parser","python","sqlite","time-zones","timezone","timezone-data","tzdata","windows-timezone"],"latest_commit_sha":null,"homepage":"https://github.com/ikelaiah/tzbundler","language":"Python","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/ikelaiah.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"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,"zenodo":null}},"created_at":"2025-07-26T12:14:13.000Z","updated_at":"2025-07-28T09:31:21.000Z","dependencies_parsed_at":"2025-07-28T11:25:15.746Z","dependency_job_id":null,"html_url":"https://github.com/ikelaiah/tzbundler","commit_stats":null,"previous_names":["ikelaiah/tzbundler"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/ikelaiah/tzbundler","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikelaiah%2Ftzbundler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikelaiah%2Ftzbundler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikelaiah%2Ftzbundler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikelaiah%2Ftzbundler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ikelaiah","download_url":"https://codeload.github.com/ikelaiah/tzbundler/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikelaiah%2Ftzbundler/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29476300,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-15T10:25:47.032Z","status":"ssl_error","status_checked_at":"2026-02-15T10:25:01.815Z","response_time":118,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["bundler","cldr","daylight-saving","dst","iana","json","parser","python","sqlite","time-zones","timezone","timezone-data","tzdata","windows-timezone"],"created_at":"2026-02-15T11:13:58.779Z","updated_at":"2026-02-15T11:14:00.724Z","avatar_url":"https://github.com/ikelaiah.png","language":"Python","readme":"\n# 🌏 tzbundler: IANA Time Zone Database Parser and Bundler\n\n[![Version](https://img.shields.io/badge/version-1.0.1-blueviolet.svg)](https://github.com/ikelaiah/tzbundler/releases)\n[![Python](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![IANA tzdata](https://img.shields.io/badge/IANA-tzdata%202025b-green.svg)](https://www.iana.org/time-zones)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/logo-v3-320.png\" alt=\"tzbundler logo\" style=\"max-width:100%; height:auto;\"\u003e\n\u003c/p\u003e\n\n**Version: 1.0.1**\n\nA Python tool that parses IANA tzdata files and converts them into machine-readable formats (JSON and SQLite). Perfect for applications, research, or data analysis involving time zones. Includes Windows timezone mappings for cross-platform compatibility.\n\nOr you can simply use the pre-generated bundle from `tzdata/` folder or [the Releases page](https://github.com/ikelaiah/tzbundler/releases).\n\n## 🗂️ Table of Contents\n\n- [🌏 tzbundler: IANA Time Zone Database Parser and Bundler](#-tzbundler-iana-time-zone-database-parser-and-bundler)\n  - [🗂️ Table of Contents](#️-table-of-contents)\n  - [🎯 Who Should Use tzbundler?](#-who-should-use-tzbundler)\n  - [✨ Features](#-features)\n  - [🚀 Quick Start](#-quick-start)\n  - [🚀 Quick Start - Just Download!](#-quick-start---just-download)\n  - [📊 Data Model](#-data-model)\n    - [Zone](#zone)\n    - [🔄 Transition](#-transition)\n    - [📏 Rule](#-rule)\n  - [📁 Input Files](#-input-files)\n  - [📤 Output Files](#-output-files)\n    - [📝 JSON Format (`combined.json`)](#-json-format-combinedjson)\n    - [💾 SQLite Database (`combined.sqlite`)](#-sqlite-database-combinedsqlite)\n      - [zones](#zones)\n      - [transitions](#transitions)\n      - [rules](#rules)\n      - [windows\\_mapping](#windows_mapping)\n  - [🪟 Windows Timezone Support](#-windows-timezone-support)\n    - [Example Usage](#example-usage)\n    - [SQL Query Examples for Windows Mappings](#sql-query-examples-for-windows-mappings)\n  - [❓ How to Use the Rules (DST Logic)](#-how-to-use-the-rules-dst-logic)\n    - [How to Determine DST Status for a Date](#how-to-determine-dst-status-for-a-date)\n      - [Step 1: Find the Active Transition](#step-1-find-the-active-transition)\n      - [Step 2: Check for DST Rules](#step-2-check-for-dst-rules)\n      - [Step 3: Find Applicable Rules for Your Year](#step-3-find-applicable-rules-for-your-year)\n      - [Step 4: Calculate Rule Dates](#step-4-calculate-rule-dates)\n      - [Step 5: Apply Hemisphere Logic](#step-5-apply-hemisphere-logic)\n      - [Step 6: Handle Edge Cases](#step-6-handle-edge-cases)\n    - [Example: Australia/Sydney on May 23, 2030](#example-australiasydney-on-may-23-2030)\n  - [🗄️ File Structure](#️-file-structure)\n  - [🧪 Testing](#-testing)\n  - [💡 Use Cases](#-use-cases)\n  - [📦 Installation \\\u0026 Requirements](#-installation--requirements)\n  - [⚙️ Important Design Decision](#️-important-design-decision)\n  - [🛡️ Error Handling and Robustness](#️-error-handling-and-robustness)\n  - [🔗 Resources](#-resources)\n  - [🤝 Contributing](#-contributing)\n  - [📝 License](#-license)\n  - [🙏 Acknowledgements](#-acknowledgements)\n\n## 🎯 Who Should Use tzbundler?\n\n- App developers who need reliable time zone handling\n- Researchers working on temporal/historical datasets\n- Anyone who wants a cross-language-compatible tzdata format\n- Developers needing Windows timezone compatibility\n\n## ✨ Features\n\n- **Simple one-command operation**: Just run `python make_tz_bundle.py`\n- **Multiple output formats**: JSON and SQLite database\n- **Complete data extraction**: Zones, transitions, rules, and aliases\n- **Windows timezone support**: Official Windows timezone mappings from Unicode CLDR\n- **Rich metadata**: Country codes, coordinates, and comments\n- **Version tracking**: Automatically includes tzdata version info\n- **Consumer-driven DST logic**: Raw rule data provided for flexible DST calculations\n\n## 🚀 Quick Start\n\n```bash\npython run_tzbundler.py\n```\n\nThis single command will:\n\n1. Fetch the latest IANA tzdata\n2. Download Windows timezone mappings from Unicode CLDR\n3. Extract and parse all files\n4. Generate `combined.json` and `combined.sqlite` in the `tzdata/` folder\n\n## 🚀 Quick Start - Just Download!\n\nUse the pre-generated `.json` or `.sqlite` bundle from `tzdata/` folder or [the Releases page](https://github.com/ikelaiah/tzbundler/releases).\n\n## 📊 Data Model\n\n### Zone\n\nRepresents a time zone with its complete history and metadata.\n\n```python\n@dataclass\nclass Zone:\n    name: str                       # e.g., \"Asia/Seoul\"\n    country_code: str               # e.g., \"KR\" \n    latitude: str                   # from coordinates\n    longitude: str                  # from coordinates  \n    comment: str                    # optional description\n    transitions: List[Transition]   # historical transitions\n    aliases: List[str]              # alternative names\n    win_names: List[str]            # Windows timezone names\n```\n\n### 🔄 Transition\n\nRepresents a period in a zone's history (offset changes, DST periods, etc.).\n\n\u003e **Note**: DST status is not pre-calculated. Consumers should use the rules data to determine DST as needed.\n\n```python\n@dataclass  \nclass Transition:\n    to_utc: Optional[str]      # when this period ends (IANA UNTIL; empty string if ongoing)\n    offset: str                # UTC offset (e.g., \"+09:00\")\n    abbr: str                  # abbreviation (e.g., \"KST\", \"JST\")\n    # rule_name: Optional[str] # attached as attribute during parsing\n```\n\n### 📏 Rule\n\nRepresents a single DST rule definition (from a Rule line in tzdata).\n\n```json\n\"rules\": {\n  \"Japan\": [\n    {\n      \"from\": \"1948\",\n      \"to\": \"only\",\n      \"type\": \"-\",\n      \"in\": \"Sep\",\n      \"on\": \"10\",\n      \"at\": \"0:00\",\n      \"save\": \"1:00\",\n      \"letter\": \"D\"\n    }\n  ]\n}\n```\n\n## 📁 Input Files\n\nThe tool processes these IANA tzdata files:\n\n| File Category | Files | Contains |\n|---------------|-------|----------|\n| **Zone Data** | `africa`, `antarctica`, `asia`, `australasia`, `europe`, `northamerica`, `southamerica` | Zone blocks, Rule lines, Link lines |\n| **Additional** | `etcetera`, `backward`, `backzone` | Extra zones and compatibility aliases |\n| **Metadata** | `zone1970.tab` | Country codes, coordinates, comments |\n| **Version** | `version` | tzdata release version |\n| **Windows Mappings** | `windowsZones.xml` | Windows-IANA timezone mappings from Unicode CLDR |\n\n## 📤 Output Files\n\n### 📝 JSON Format (`combined.json`)\n\n```json\n{\n  \"timezones\": {\n    \"Asia/Seoul\": {\n      \"country_code\": \"KR\",\n      \"coordinates\": \"+3733+12658\", \n      \"comment\": \"\",\n      \"transitions\": [\n        {\n          \"to_utc\": \"1948 May 8\",\n          \"offset\": \"+08:30\",\n          \"abbr\": \"KST\",\n          \"rule_name\": null\n        },\n        {\n          \"to_utc\": \"\",\n          \"offset\": \"+09:00\",\n          \"abbr\": \"KDT\",\n          \"rule_name\": \"Korea\"\n        }\n      ],\n      \"aliases\": [\"ROK\"],\n      \"win_names\": [\"Korea Standard Time\"]\n    }\n  },\n  \"rules\": {\n    \"Korea\": [\n      {\n        \"from\": \"1948\",\n        \"to\": \"only\",\n        \"type\": \"-\",\n        \"in\": \"May\",\n        \"on\": \"8\",\n        \"at\": \"0:00\",\n        \"save\": \"1:00\",\n        \"letter\": \"D\"\n      }\n    ]\n  },\n  \"windows_mapping\": {\n    \"Korea Standard Time\": [\"Asia/Seoul\"]\n  },\n  \"_version\": \"2025b\"\n}\n```\n\n### 💾 SQLite Database (`combined.sqlite`)\n\nFour normalized tables:\n\n#### zones\n\n- `name` (TEXT PRIMARY KEY)\n- `country_code` (TEXT)\n- `latitude` (TEXT)\n- `longitude` (TEXT)\n- `comment` (TEXT)\n\n#### transitions\n\n- `zone_name` (TEXT)\n- `to_utc` (TEXT)\n- `offset` (TEXT)\n- `abbr` (TEXT)\n- `rule_name` (TEXT)\n\n#### rules\n\n- `rule_name` (TEXT)\n- `from_year` (TEXT)\n- `to_year` (TEXT)\n- `type` (TEXT)\n- `in_month` (TEXT)\n- `on_day` (TEXT)\n- `at_time` (TEXT)\n- `save` (TEXT)\n- `letter` (TEXT)\n\n#### windows_mapping\n\n- `windows_name` (TEXT) - Windows timezone name\n- `iana_name` (TEXT) - IANA timezone name\n\n## 🪟 Windows Timezone Support\n\ntzbundler includes official Windows timezone mappings from the Unicode CLDR project:\n\n- **Bidirectional mappings**: IANA ↔ Windows timezone names\n- **Authoritative source**: Uses the official Unicode CLDR windowsZones.xml\n- **Cross-platform compatibility**: Perfect for applications that need to work with both IANA and Windows timezones\n\n### Example Usage\n\n```python\n# Find Windows name for IANA timezone\nasia_seoul_windows = timezones[\"Asia/Seoul\"][\"win_names\"]  # [\"Korea Standard Time\"]\n\n# Find IANA zones for Windows timezone\nkorea_iana_zones = windows_mapping[\"Korea Standard Time\"]  # [\"Asia/Seoul\"]\n```\n\n### SQL Query Examples for Windows Mappings\n\n```sql\n-- Find Windows timezone name for an IANA zone\nSELECT z.name, wm.windows_name \nFROM zones z \nJOIN windows_mapping wm ON z.name = wm.iana_name \nWHERE z.name = 'Asia/Seoul';\n\n-- List all Windows timezones and their IANA equivalents\nSELECT windows_name, GROUP_CONCAT(iana_name, ', ') as iana_zones\nFROM windows_mapping \nGROUP BY windows_name;\n\n-- Find zones that have Windows mappings\nSELECT z.name, z.country_code \nFROM zones z \nWHERE EXISTS (SELECT 1 FROM windows_mapping wm WHERE wm.iana_name = z.name);\n```\n\n## ❓ How to Use the Rules (DST Logic)\n\n\u003e **Important:**  \n\u003e tzbundler provides raw rule data—**you must calculate DST status yourself** using the rules and transitions.\n\n### How to Determine DST Status for a Date\n\nTo determine if DST is active for a specific zone and date (e.g., \"Australia/Sydney\" on May 23, 2030):\n\n#### Step 1: Find the Active Transition\n\n- Get the **current transition** for your zone (usually the last one in the transitions array)\n- This gives you the base UTC offset and rule name\n\n#### Step 2: Check for DST Rules  \n\n- If `rule_name` is `null` or `\"-\"`: **No DST** (fixed offset zone)\n- Otherwise, get the rule set: `tzdata['rules'][rule_name]`\n\n#### Step 3: Find Applicable Rules for Your Year\n\n- Look for rules where: `from_year \u003c= target_year \u003c= to_year`\n- You'll typically find **two types**:\n  - **DST start rule**: `save` \u003e 0 (e.g., `\"1:00\"`)\n  - **DST end rule**: `save` = 0 (e.g., `\"0\"`)\n\n#### Step 4: Calculate Rule Dates\n\nParse the IANA date specifications:\n\n- `\"lastSun\"` = Last Sunday of the month\n- `\"Sun\u003e=8\"` = First Sunday on or after the 8th\n- `\"15\"` = 15th day of the month\n\n#### Step 5: Apply Hemisphere Logic\n\n- **Northern Hemisphere** (US/Europe): DST typically Mar-Nov\n  - `DST active = start_date \u003c= target_date \u003c end_date`\n- **Southern Hemisphere** (Australia): DST typically Oct-Apr  \n  - `DST active = target_date \u003e= start_date OR target_date \u003c end_date`\n\n#### Step 6: Handle Edge Cases\n\n- **Ambiguous times**: When clocks \"fall back\", some times occur twice\n- **Invalid times**: When clocks \"spring forward\", some times don't exist  \n- **Time suffixes**: `s`=standard, `u`/`g`/`z`=UTC, `w`=wall (default)\n\n### Example: Australia/Sydney on May 23, 2030\n\n```python\n# 1. Active transition\ntransition = tzdata['timezones']['Australia/Sydney']['transitions'][-1]\n# Result: offset=\"+10:00\", rule_name=\"AN\"\n\n# 2. Get DST rules\nan_rules = tzdata['rules']['AN']\n\n# 3. Find 2030 rules\ncurrent_rules = [r for r in an_rules if r['from'] \u003c= '2030' \u003c= r.get('to', '9999')]\n# DST ends: Apr Sun\u003e=1 (April 7, 2030)  \n# DST starts: Oct Sun\u003e=1 (October 6, 2030)\n\n# 4. Check date\ntest_date = May 23, 2030\n# May 23 is AFTER April 7 (DST end) and BEFORE October 6 (DST start)\n# Therefore: DST is NOT active\n\n# 5. Result\nis_dst = False\noffset = \"+10:00\"  # Base offset only\nabbreviation = \"AEST\"  # AE%sT with %s=\"S\" for Standard\n\n\n## 🕐 How to Calculate DST Status (Detailed)\n\nSee [How to Calculate DST Status](docs/how-to-calculate-dst-status.md)\n\n## ❓ How Parsing Works (Detailed)\n\nSee [How Parsing Works](docs/how-parsing-works.md)\n\n### Data Processing Flow\n\n```txt\nRaw tzdata files → Parse zones/rules/links → Enrich with metadata → Add Windows mappings → Output JSON/SQLite\n```\n\n## 🗄️ File Structure\n\n```txt\nassets/                 # Project assets (e.g., logos)\ndocs/                   # Documentation\nexample/                # Example data and usage\ntests/                  # Unified and supporting test scripts\n├── test_tzbundler.py   # Unified test suite for all outputs\n└── test_windowsZones.py\ntzbundler/              # Main package source code\n├── __init__.py\n├── get_latest_tz.py\n└── make_tz_bundle.py\ntzdata/                 # Processed output\n├── combined.json\n└── combined.sqlite\ntzdata_raw/             # Downloaded raw IANA and CLDR files\nCHANGELOG.md            # Release notes\nCONTRIBUTING.md         # Contribution guidelines\nLICENSE                 # License file\nREADME.md               # Project documentation\nrequirements.txt        # Python dependencies\nrun_tests.py            # Entry point to run all tests\nrun_tzbundler.py        # Main script to generate tzdata bundles\nsetup.py                # Package setup\n```\n\n## 🧪 Testing\n\nYou can run all tests in two ways:\n\n**With pytest (recommended for CI and automation):**\n\n```bash\npytest tests/test_tzbundler.py\n```\n\n**Or using the provided entry point script:**\n\n```bash\npython run_tests.py\n```\n\nThis will run all major tests (JSON, SQLite, consistency, and structure) and print a summary.\n\n## 💡 Use Cases\n\n- **Cross-Platform Applications**: Handle both IANA and Windows timezone identifiers\n- **Data Analysis**: Research time zone changes and patterns  \n- **Historical Analysis**: Track offset changes over time\n- **Compliance**: Ensure accurate time zone handling\n- **Custom DST Logic**: Implement domain-specific DST calculations\n- **Migration Projects**: Convert between Windows and IANA timezone systems\n\n## 📦 Installation \u0026 Requirements\n\n```python\n# Required Python packages\nrequests\u003e=2.25.0    # For downloading tzdata and Windows mappings\n```\n\nClone and run:\n\n```bash\ngit clone https://github.com/ikelaiah/tzbundler.git\ncd tzbundler\npip install -r requirements.txt\npython run_tzbundler.py\n```\n\n## ⚙️ Important Design Decision\n\n**tzbundler does not pre-calculate DST status.** Instead, it provides:\n\n- ✅ Raw transition data (offsets, dates, abbreviations)\n- ✅ Complete DST rule definitions  \n- ✅ Rule names linked to transitions\n- ✅ Windows timezone mappings\n- ❌ Pre-calculated DST boolean flags\n\n**Why?** This design:\n\n- Avoids bundler bugs affecting DST calculations\n- Allows consumers to implement DST logic that fits their needs\n- Enables caching and on-demand DST computation\n- Keeps complex temporal logic out of the data extraction layer\n- Provides maximum flexibility for cross-platform compatibility\n\n## 🛡️ Error Handling and Robustness\n\nThe tool includes comprehensive error handling:\n\n- **Network issues**: Gracefully handles connection failures and provides troubleshooting tips\n- **File corruption**: Validates downloaded archives and provides cleanup on failure\n- **Parsing errors**: Logs problematic lines but continues processing\n- **Missing files**: Warns about missing files but continues with available data\n- **Partial downloads**: Detects and handles incomplete downloads\n\n## 🔗 Resources\n\n- [IANA Time Zone Database](https://www.iana.org/time-zones)\n- [tzdata Format Documentation](https://data.iana.org/time-zones/theory.html)\n- [tzdata Theory File](https://data.iana.org/time-zones/theory.html) (Essential for DST implementation)\n- [Unicode CLDR WindowsZones](https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml)\n\n\n## 🤝 Contributing\n\nContributions welcome! Please feel free to submit a Pull Request.\n\n## 📝 License\n\n[MIT License](LICENSE.md)\n\n\n## 🙏 Acknowledgements\n\nSpecial thanks to the Python core developers and the wider Python community for building and maintaining the language and ecosystem that make projects like this possible.\n\nSpecial thanks to [a-blekot](https://github.com/a-blekot) for valuable feedback and suggestions on naming and IANA compatibility.\n\n\n---\n\n**Built with ❤️ for developers who need reliable timezone data**","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fikelaiah%2Ftzbundler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fikelaiah%2Ftzbundler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fikelaiah%2Ftzbundler/lists"}