https://github.com/ikelaiah/tzbundler
π Parse IANA timezone database into JSON & SQLite with Windows timezone support. Includes DST rules, historical transitions, and comprehensive metadata for timezone-aware applications.
https://github.com/ikelaiah/tzbundler
bundler cldr daylight-saving dst iana json parser python sqlite time-zones timezone timezone-data tzdata windows-timezone
Last synced: 2 months ago
JSON representation
π Parse IANA timezone database into JSON & SQLite with Windows timezone support. Includes DST rules, historical transitions, and comprehensive metadata for timezone-aware applications.
- Host: GitHub
- URL: https://github.com/ikelaiah/tzbundler
- Owner: ikelaiah
- License: mit
- Created: 2025-07-26T12:14:13.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2025-07-28T09:34:18.000Z (9 months ago)
- Last Synced: 2025-07-28T11:15:13.257Z (9 months ago)
- Topics: bundler, cldr, daylight-saving, dst, iana, json, parser, python, sqlite, time-zones, timezone, timezone-data, tzdata, windows-timezone
- Language: Python
- Homepage: https://github.com/ikelaiah/tzbundler
- Size: 4.93 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# π tzbundler: IANA Time Zone Database Parser and Bundler
[](https://github.com/ikelaiah/tzbundler/releases)
[](https://www.python.org/downloads/)
[](https://opensource.org/licenses/MIT)
[](https://www.iana.org/time-zones)
**Version: 1.0.1**
A 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.
Or you can simply use the pre-generated bundle from `tzdata/` folder or [the Releases page](https://github.com/ikelaiah/tzbundler/releases).
## ποΈ Table of Contents
- [π tzbundler: IANA Time Zone Database Parser and Bundler](#-tzbundler-iana-time-zone-database-parser-and-bundler)
- [ποΈ Table of Contents](#οΈ-table-of-contents)
- [π― Who Should Use tzbundler?](#-who-should-use-tzbundler)
- [β¨ Features](#-features)
- [π Quick Start](#-quick-start)
- [π Quick Start - Just Download!](#-quick-start---just-download)
- [π Data Model](#-data-model)
- [Zone](#zone)
- [π Transition](#-transition)
- [π Rule](#-rule)
- [π Input Files](#-input-files)
- [π€ Output Files](#-output-files)
- [π JSON Format (`combined.json`)](#-json-format-combinedjson)
- [πΎ SQLite Database (`combined.sqlite`)](#-sqlite-database-combinedsqlite)
- [zones](#zones)
- [transitions](#transitions)
- [rules](#rules)
- [windows\_mapping](#windows_mapping)
- [πͺ Windows Timezone Support](#-windows-timezone-support)
- [Example Usage](#example-usage)
- [SQL Query Examples for Windows Mappings](#sql-query-examples-for-windows-mappings)
- [β How to Use the Rules (DST Logic)](#-how-to-use-the-rules-dst-logic)
- [How to Determine DST Status for a Date](#how-to-determine-dst-status-for-a-date)
- [Step 1: Find the Active Transition](#step-1-find-the-active-transition)
- [Step 2: Check for DST Rules](#step-2-check-for-dst-rules)
- [Step 3: Find Applicable Rules for Your Year](#step-3-find-applicable-rules-for-your-year)
- [Step 4: Calculate Rule Dates](#step-4-calculate-rule-dates)
- [Step 5: Apply Hemisphere Logic](#step-5-apply-hemisphere-logic)
- [Step 6: Handle Edge Cases](#step-6-handle-edge-cases)
- [Example: Australia/Sydney on May 23, 2030](#example-australiasydney-on-may-23-2030)
- [ποΈ File Structure](#οΈ-file-structure)
- [π§ͺ Testing](#-testing)
- [π‘ Use Cases](#-use-cases)
- [π¦ Installation \& Requirements](#-installation--requirements)
- [βοΈ Important Design Decision](#οΈ-important-design-decision)
- [π‘οΈ Error Handling and Robustness](#οΈ-error-handling-and-robustness)
- [π Resources](#-resources)
- [π€ Contributing](#-contributing)
- [π License](#-license)
- [π Acknowledgements](#-acknowledgements)
## π― Who Should Use tzbundler?
- App developers who need reliable time zone handling
- Researchers working on temporal/historical datasets
- Anyone who wants a cross-language-compatible tzdata format
- Developers needing Windows timezone compatibility
## β¨ Features
- **Simple one-command operation**: Just run `python make_tz_bundle.py`
- **Multiple output formats**: JSON and SQLite database
- **Complete data extraction**: Zones, transitions, rules, and aliases
- **Windows timezone support**: Official Windows timezone mappings from Unicode CLDR
- **Rich metadata**: Country codes, coordinates, and comments
- **Version tracking**: Automatically includes tzdata version info
- **Consumer-driven DST logic**: Raw rule data provided for flexible DST calculations
## π Quick Start
```bash
python run_tzbundler.py
```
This single command will:
1. Fetch the latest IANA tzdata
2. Download Windows timezone mappings from Unicode CLDR
3. Extract and parse all files
4. Generate `combined.json` and `combined.sqlite` in the `tzdata/` folder
## π Quick Start - Just Download!
Use the pre-generated `.json` or `.sqlite` bundle from `tzdata/` folder or [the Releases page](https://github.com/ikelaiah/tzbundler/releases).
## π Data Model
### Zone
Represents a time zone with its complete history and metadata.
```python
@dataclass
class Zone:
name: str # e.g., "Asia/Seoul"
country_code: str # e.g., "KR"
latitude: str # from coordinates
longitude: str # from coordinates
comment: str # optional description
transitions: List[Transition] # historical transitions
aliases: List[str] # alternative names
win_names: List[str] # Windows timezone names
```
### π Transition
Represents a period in a zone's history (offset changes, DST periods, etc.).
> **Note**: DST status is not pre-calculated. Consumers should use the rules data to determine DST as needed.
```python
@dataclass
class Transition:
to_utc: Optional[str] # when this period ends (IANA UNTIL; empty string if ongoing)
offset: str # UTC offset (e.g., "+09:00")
abbr: str # abbreviation (e.g., "KST", "JST")
# rule_name: Optional[str] # attached as attribute during parsing
```
### π Rule
Represents a single DST rule definition (from a Rule line in tzdata).
```json
"rules": {
"Japan": [
{
"from": "1948",
"to": "only",
"type": "-",
"in": "Sep",
"on": "10",
"at": "0:00",
"save": "1:00",
"letter": "D"
}
]
}
```
## π Input Files
The tool processes these IANA tzdata files:
| File Category | Files | Contains |
|---------------|-------|----------|
| **Zone Data** | `africa`, `antarctica`, `asia`, `australasia`, `europe`, `northamerica`, `southamerica` | Zone blocks, Rule lines, Link lines |
| **Additional** | `etcetera`, `backward`, `backzone` | Extra zones and compatibility aliases |
| **Metadata** | `zone1970.tab` | Country codes, coordinates, comments |
| **Version** | `version` | tzdata release version |
| **Windows Mappings** | `windowsZones.xml` | Windows-IANA timezone mappings from Unicode CLDR |
## π€ Output Files
### π JSON Format (`combined.json`)
```json
{
"timezones": {
"Asia/Seoul": {
"country_code": "KR",
"coordinates": "+3733+12658",
"comment": "",
"transitions": [
{
"to_utc": "1948 May 8",
"offset": "+08:30",
"abbr": "KST",
"rule_name": null
},
{
"to_utc": "",
"offset": "+09:00",
"abbr": "KDT",
"rule_name": "Korea"
}
],
"aliases": ["ROK"],
"win_names": ["Korea Standard Time"]
}
},
"rules": {
"Korea": [
{
"from": "1948",
"to": "only",
"type": "-",
"in": "May",
"on": "8",
"at": "0:00",
"save": "1:00",
"letter": "D"
}
]
},
"windows_mapping": {
"Korea Standard Time": ["Asia/Seoul"]
},
"_version": "2025b"
}
```
### πΎ SQLite Database (`combined.sqlite`)
Four normalized tables:
#### zones
- `name` (TEXT PRIMARY KEY)
- `country_code` (TEXT)
- `latitude` (TEXT)
- `longitude` (TEXT)
- `comment` (TEXT)
#### transitions
- `zone_name` (TEXT)
- `to_utc` (TEXT)
- `offset` (TEXT)
- `abbr` (TEXT)
- `rule_name` (TEXT)
#### rules
- `rule_name` (TEXT)
- `from_year` (TEXT)
- `to_year` (TEXT)
- `type` (TEXT)
- `in_month` (TEXT)
- `on_day` (TEXT)
- `at_time` (TEXT)
- `save` (TEXT)
- `letter` (TEXT)
#### windows_mapping
- `windows_name` (TEXT) - Windows timezone name
- `iana_name` (TEXT) - IANA timezone name
## πͺ Windows Timezone Support
tzbundler includes official Windows timezone mappings from the Unicode CLDR project:
- **Bidirectional mappings**: IANA β Windows timezone names
- **Authoritative source**: Uses the official Unicode CLDR windowsZones.xml
- **Cross-platform compatibility**: Perfect for applications that need to work with both IANA and Windows timezones
### Example Usage
```python
# Find Windows name for IANA timezone
asia_seoul_windows = timezones["Asia/Seoul"]["win_names"] # ["Korea Standard Time"]
# Find IANA zones for Windows timezone
korea_iana_zones = windows_mapping["Korea Standard Time"] # ["Asia/Seoul"]
```
### SQL Query Examples for Windows Mappings
```sql
-- Find Windows timezone name for an IANA zone
SELECT z.name, wm.windows_name
FROM zones z
JOIN windows_mapping wm ON z.name = wm.iana_name
WHERE z.name = 'Asia/Seoul';
-- List all Windows timezones and their IANA equivalents
SELECT windows_name, GROUP_CONCAT(iana_name, ', ') as iana_zones
FROM windows_mapping
GROUP BY windows_name;
-- Find zones that have Windows mappings
SELECT z.name, z.country_code
FROM zones z
WHERE EXISTS (SELECT 1 FROM windows_mapping wm WHERE wm.iana_name = z.name);
```
## β How to Use the Rules (DST Logic)
> **Important:**
> tzbundler provides raw rule dataβ**you must calculate DST status yourself** using the rules and transitions.
### How to Determine DST Status for a Date
To determine if DST is active for a specific zone and date (e.g., "Australia/Sydney" on May 23, 2030):
#### Step 1: Find the Active Transition
- Get the **current transition** for your zone (usually the last one in the transitions array)
- This gives you the base UTC offset and rule name
#### Step 2: Check for DST Rules
- If `rule_name` is `null` or `"-"`: **No DST** (fixed offset zone)
- Otherwise, get the rule set: `tzdata['rules'][rule_name]`
#### Step 3: Find Applicable Rules for Your Year
- Look for rules where: `from_year <= target_year <= to_year`
- You'll typically find **two types**:
- **DST start rule**: `save` > 0 (e.g., `"1:00"`)
- **DST end rule**: `save` = 0 (e.g., `"0"`)
#### Step 4: Calculate Rule Dates
Parse the IANA date specifications:
- `"lastSun"` = Last Sunday of the month
- `"Sun>=8"` = First Sunday on or after the 8th
- `"15"` = 15th day of the month
#### Step 5: Apply Hemisphere Logic
- **Northern Hemisphere** (US/Europe): DST typically Mar-Nov
- `DST active = start_date <= target_date < end_date`
- **Southern Hemisphere** (Australia): DST typically Oct-Apr
- `DST active = target_date >= start_date OR target_date < end_date`
#### Step 6: Handle Edge Cases
- **Ambiguous times**: When clocks "fall back", some times occur twice
- **Invalid times**: When clocks "spring forward", some times don't exist
- **Time suffixes**: `s`=standard, `u`/`g`/`z`=UTC, `w`=wall (default)
### Example: Australia/Sydney on May 23, 2030
```python
# 1. Active transition
transition = tzdata['timezones']['Australia/Sydney']['transitions'][-1]
# Result: offset="+10:00", rule_name="AN"
# 2. Get DST rules
an_rules = tzdata['rules']['AN']
# 3. Find 2030 rules
current_rules = [r for r in an_rules if r['from'] <= '2030' <= r.get('to', '9999')]
# DST ends: Apr Sun>=1 (April 7, 2030)
# DST starts: Oct Sun>=1 (October 6, 2030)
# 4. Check date
test_date = May 23, 2030
# May 23 is AFTER April 7 (DST end) and BEFORE October 6 (DST start)
# Therefore: DST is NOT active
# 5. Result
is_dst = False
offset = "+10:00" # Base offset only
abbreviation = "AEST" # AE%sT with %s="S" for Standard
## π How to Calculate DST Status (Detailed)
See [How to Calculate DST Status](docs/how-to-calculate-dst-status.md)
## β How Parsing Works (Detailed)
See [How Parsing Works](docs/how-parsing-works.md)
### Data Processing Flow
```txt
Raw tzdata files β Parse zones/rules/links β Enrich with metadata β Add Windows mappings β Output JSON/SQLite
```
## ποΈ File Structure
```txt
assets/ # Project assets (e.g., logos)
docs/ # Documentation
example/ # Example data and usage
tests/ # Unified and supporting test scripts
βββ test_tzbundler.py # Unified test suite for all outputs
βββ test_windowsZones.py
tzbundler/ # Main package source code
βββ __init__.py
βββ get_latest_tz.py
βββ make_tz_bundle.py
tzdata/ # Processed output
βββ combined.json
βββ combined.sqlite
tzdata_raw/ # Downloaded raw IANA and CLDR files
CHANGELOG.md # Release notes
CONTRIBUTING.md # Contribution guidelines
LICENSE # License file
README.md # Project documentation
requirements.txt # Python dependencies
run_tests.py # Entry point to run all tests
run_tzbundler.py # Main script to generate tzdata bundles
setup.py # Package setup
```
## π§ͺ Testing
You can run all tests in two ways:
**With pytest (recommended for CI and automation):**
```bash
pytest tests/test_tzbundler.py
```
**Or using the provided entry point script:**
```bash
python run_tests.py
```
This will run all major tests (JSON, SQLite, consistency, and structure) and print a summary.
## π‘ Use Cases
- **Cross-Platform Applications**: Handle both IANA and Windows timezone identifiers
- **Data Analysis**: Research time zone changes and patterns
- **Historical Analysis**: Track offset changes over time
- **Compliance**: Ensure accurate time zone handling
- **Custom DST Logic**: Implement domain-specific DST calculations
- **Migration Projects**: Convert between Windows and IANA timezone systems
## π¦ Installation & Requirements
```python
# Required Python packages
requests>=2.25.0 # For downloading tzdata and Windows mappings
```
Clone and run:
```bash
git clone https://github.com/ikelaiah/tzbundler.git
cd tzbundler
pip install -r requirements.txt
python run_tzbundler.py
```
## βοΈ Important Design Decision
**tzbundler does not pre-calculate DST status.** Instead, it provides:
- β
Raw transition data (offsets, dates, abbreviations)
- β
Complete DST rule definitions
- β
Rule names linked to transitions
- β
Windows timezone mappings
- β Pre-calculated DST boolean flags
**Why?** This design:
- Avoids bundler bugs affecting DST calculations
- Allows consumers to implement DST logic that fits their needs
- Enables caching and on-demand DST computation
- Keeps complex temporal logic out of the data extraction layer
- Provides maximum flexibility for cross-platform compatibility
## π‘οΈ Error Handling and Robustness
The tool includes comprehensive error handling:
- **Network issues**: Gracefully handles connection failures and provides troubleshooting tips
- **File corruption**: Validates downloaded archives and provides cleanup on failure
- **Parsing errors**: Logs problematic lines but continues processing
- **Missing files**: Warns about missing files but continues with available data
- **Partial downloads**: Detects and handles incomplete downloads
## π Resources
- [IANA Time Zone Database](https://www.iana.org/time-zones)
- [tzdata Format Documentation](https://data.iana.org/time-zones/theory.html)
- [tzdata Theory File](https://data.iana.org/time-zones/theory.html) (Essential for DST implementation)
- [Unicode CLDR WindowsZones](https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml)
## π€ Contributing
Contributions welcome! Please feel free to submit a Pull Request.
## π License
[MIT License](LICENSE.md)
## π Acknowledgements
Special 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.
Special thanks to [a-blekot](https://github.com/a-blekot) for valuable feedback and suggestions on naming and IANA compatibility.
---
**Built with β€οΈ for developers who need reliable timezone data**