Introduction
If you’ve ever needed to show a friendly time zone abbreviation like SGT or EDT from an IANA zone name (e.g., Asia/Singapore, America/New_York), you’ve probably discovered it’s trickier than it should be. Python’s excellent zoneinfo handles time conversions, but it doesn’t give you a simple, static lookup for abbreviations.
Meet tznn — a tiny helper that maps IANA time zones to their common abbreviations with a single import.
Features:
- Need a quick SGT/EDT abbreviation from an IANA zone? Use tznn.
- Tiny, dependency-light, works cross-platform.
- Install: pip install tznn
Why this exists
A lot of apps need to display short, human-friendly zone labels alongside times (SGT, EDT, CET…), but:
- The standard library focuses on accurate conversions and offsets, not static abbreviations.
- Abbreviations can vary with DST and history; sometimes you just want a stable label for UI or configuration.
tznn provides a straightforward answer: a packaged JSON mapping from IANA zone names to common abbreviations.
Let's look at simple code from default python, problem stament, I want to get TimeZone code at New York and Singapore
from datetime import datetime
from zoneinfo import ZoneInfo
dt_utc = datetime(2025, 9, 23, 3, 2, 7, tzinfo=ZoneInfo("UTC"))
dt_ny = dt_utc.astimezone(ZoneInfo("America/New_York"))
dt_sg = dt_utc.astimezone(ZoneInfo("Asia/Singapore"))
print(dt_ny.strftime("%d/%m/%Y %H:%M:%S %Z %z")) # → 22/09/2025 23:02:07 EDT -0400
print(dt_sg.strftime("%d/%m/%Y %H:%M:%S %Z %z")) # → 23/09/2025 11:02:07 +08 +0800
In .NET, you can try using NodaTime.
using NodaTime;
using NodaTime.Text;
// UTC instant
var instant = Instant.FromUtc(2025, 9, 23, 3, 2, 7);
var nyZone = DateTimeZoneProviders.Tzdb["America/New_York"];
var sgZone = DateTimeZoneProviders.Tzdb["Asia/Singapore"];
var nyTime = instant.InZone(nyZone);
var sgTime = instant.InZone(sgZone);
// Use NodaTime's offset pattern
Console.WriteLine($"{nyTime:dd/MM/yyyy HH:mm:ss} {nyTime.Offset}");
Console.WriteLine($"{sgTime:dd/MM/yyyy HH:mm:ss} {sgTime.Offset}");
// If you also want the zone ID
Console.WriteLine($"{nyTime:dd/MM/yyyy HH:mm:ss} {nyTime.Zone.Id} {nyTime.Offset}");
Console.WriteLine($"{sgTime:dd/MM/yyyy HH:mm:ss} {sgTime.Zone.Id} {sgTime.Offset}");
The expected output for Singapore is SGT, but it returns ?????? instead. This is because zoneinfo does not include static abbreviations.
When I look into the details at zoneinfo doc, and try to decompress the IANA time zone database, I founded some interesting things:
- Becasue the history of time zones is complex and changes over time, the same location may have different abbreviations at different times (e.g., EST vs. EDT for New York).
Example : Viet Name using GMT+7, but the abbreviation is ICT, but we are using location Asia/Ho_Chi_Minh match with GMT+7 for the same time zone with Russia; Indochina; Christmas Island
The code details from timezone source code )
# +07
XX +1345+10031 Asia/Bangkok Russia; Indochina; Christmas Island
- The zoneinfo module focuses on accurate time conversions and offsets, not on providing a static mapping of abbreviations. That means it doesn't include a simple way to look up abbreviations for display purposes, and replaces them with numeric offsets like +0800.
What tznn does ?
- List available IANA time zones
- Look up the abbreviation (e.g., SGT, EDT) for a zone name
- Return the entire zone → abbreviation mapping
It’s intentionally simple and fast. Abbreviations are static values from timezone.json—they’re not date-aware.
Install
Online via PyPI:
pip install tznn
Upgrade:
pip install -U tznn
From source:
pip install .
pip install -r requirements.txt
Note: On Windows, tzdata
may be installed automatically if needed.
Quick start
from tznn import tznn
tz = tznn()
# 1) Get a sorted list of available IANA time zone names
zones = tz.get_available_time_zones()
print(len(zones), zones[:5])
# 2) Get the abbreviation for a known time zone
print(tz.get_abbr("Asia/Singapore")) # -> "SGT"
print(tz.get_abbr("Asia/Ho_Chi_Minh")) # -> "ICT"
print(tz.get_abbr("America/New_York")) # -> e.g., "EDT"
# 3) Get the full mapping of zone -> abbreviation
mapping = tz.get_all_available_time_zones()
print(mapping["America/New_York"]) # -> "EDT"
A note on zoneinfo
zoneinfo
is perfect for conversions and offsets, but it’s not a direct answer for static abbreviations. For example:
from datetime import datetime
from zoneinfo import ZoneInfo
dt_utc = datetime(2025, 9, 23, 3, 2, 7, tzinfo=ZoneInfo("UTC"))
dt_vn = dt_utc.astimezone(ZoneInfo("Asia/Ho_Chi_Minh"))
print(dt_vn.strftime("%d/%m/%Y %H:%M:%S %Z %z")) # → 23/09/2025 10:02:07 ICT +0700
tznn complements this by giving you a fast, static label when you just need to display an abbreviation.
API in 30 seconds
get_available_time_zones() -> list[str]
- Sorted list of IANA zone names in the data file.
get_all_available_time_zones() -> dict[str, str]
- Entire mapping
zone_name -> abbreviation
.
- Entire mapping
get_abbr(tz_name: str) -> str
- Abbreviation for a given zone name.
- Raises
ValueError
if the zone doesn’t exist in the mapping.
Limitations
- Abbreviations are static and don’t reflect historical or future DST changes.
- If you need date-aware correctness, combine this with the standard library
zoneinfo
for conversions and offsets.
Quality and releases
- CI runs on multiple Python versions (3.9–3.12).
- Publishing is automated via GitHub Actions on release.
- MIT licensed.
Knowledge
- https://adamj.eu/tech/2021/05/06/how-to-list-all-timezones-in-python/
- https://stackoverflow.com/questions/78580391/zoneinfo-is-missing-timezone-names-that-pytz-has
- https://docs.python.org/3/library/zoneinfo.html
- https://github.com/python/tzdata/issues/111
- https://discuss.python.org/t/get-local-time-zone/4169/10
- https://www.iana.org/time-zones
- https://data.iana.org/time-zones/releases/
Interested with history from zoneinfo --- IGNORE ---
I seen some interesting things in message from source code, the war in Viet Nam make the time zone change a lot, and the details are not clear
# Zone NAME STDOFF RULES FORMAT [UNTIL]
#STDOFF 7:06:30.13
Zone Asia/Ho_Chi_Minh 7:06:30 - LMT 1906 Jul 1
7:06:30 - PLMT 1911 May 1 # Phù Liễn MT
7:00 - %z 1942 Dec 31 23:00
8:00 - %z 1945 Mar 14 23:00
9:00 - %z 1945 Sep 1 24:00
7:00 - %z 1947 Apr 1
8:00 - %z 1955 Jul 1 01:00
7:00 - %z 1959 Dec 31 23:00
8:00 - %z 1975 Jun 13
7:00 - %z
# From Paul Eggert (2019-02-19):
#
# The Ho Chi Minh entry suffices for most purposes as it agrees with all of
# Vietnam since 1975-06-13. Presumably clocks often changed in south Vietnam
# in the early 1970s as locations changed hands during the war; however the
# details are unknown and would likely be too voluminous for this database.
#
# For timestamps in north Vietnam back to 1970 (the tzdb cutoff),
# use Asia/Bangkok; see the VN entries in the file zone1970.tab.
# For timestamps before 1970, see Asia/Hanoi in the file 'backzone'.
And so many backward in source code give me learning a lot about the history base on time zone and country changed
# Alternate names for the same location
# Link TARGET LINK-NAME #= TARGET1
Link Africa/Nairobi Africa/Asmera #= Africa/Asmara
Link America/Nuuk America/Godthab
Link Asia/Ashgabat Asia/Ashkhabad
Link Asia/Kolkata Asia/Calcutta
Link Asia/Shanghai Asia/Chungking #= Asia/Chongqing
Link Asia/Dhaka Asia/Dacca
# Istanbul is in both continents.
Link Europe/Istanbul Asia/Istanbul
Link Asia/Kathmandu Asia/Katmandu
Link Asia/Macau Asia/Macao
Link Asia/Yangon Asia/Rangoon
Link Asia/Ho_Chi_Minh Asia/Saigon
Link Asia/Thimphu Asia/Thimbu
Link Asia/Makassar Asia/Ujung_Pandang
Link Asia/Ulaanbaatar Asia/Ulan_Bator
Link Atlantic/Faroe Atlantic/Faeroe
Link Europe/Kyiv Europe/Kiev
# Classically, Cyprus is in Asia; e.g. see Herodotus, Histories, I.72.
# However, for various reasons many users expect to find it under Europe.
Link Asia/Nicosia Europe/Nicosia
Link Pacific/Honolulu HST
Link America/Los_Angeles PST8PDT
Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei
Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk