A Bash function that parses messy, natural-language time expressions — with or without timezone abbreviations — and outputs clean ISO 8601 timestamps in Gothenburg local time (Europe/Stockholm).
People communicate times like this:
"Saturday, July 11th at 2pm EST"
This string contains three traps:
- Natural language. "July 11th", "at 2pm", weekday names — non-standardised, locale-dependent, ambiguous.
- Timezone abbreviations are broken by design. "EST" literally means UTC−5, always. But in July, the US East Coast is on EDT (UTC−4). Anyone typing "EST" in summer almost certainly means "Eastern Time" generically — yet most tools interpret the abbreviation literally, producing a silent one-hour error.
- No consistent output. Even when the input is parsed correctly, the result floats in whatever timezone the input used, requiring a second mental conversion to your own local time.
It takes a freeform date/time string, figures out the intended source timezone, converts to Europe/Stockholm (Gothenburg), and prints the result as YYYY-MM-DD HH:MM.
$ to_gbgt "Saturday, July 11th at 2pm EST"
2026-07-11 20:00No offset printed, no ambiguity, no mental math.
Add the function to your ~/.bashrc or ~/.zshrc:
source ~/.config/to_gbgt/to_gbgt.shOr paste the function body directly into your rc file.
Save the script as ~/.local/bin/to_gbgt, make it executable:
chmod +x ~/.local/bin/to_gbgtEnsure ~/.local/bin is in your $PATH.
to_gbgt "" [timezone abbreviation]The timezone can be passed as a second argument, or it can be embedded in the time string itself. If no timezone is detected, the input is assumed to be Gothenburg local time.
# Full natural language with embedded zone
to_gbgt "Saturday, July 11th at 2pm EST"
# → 2026-07-11 20:00 (EST treated as America/New_York → EDT in July → CEST in Gothenburg)
# Short form
to_gbgt "July 11 2pm" America/New_York
# → 2026-07-11 20:00
# Winter — DST correctly absent on both sides
to_gbgt "Dec 25 9am PST"
# → 2025-12-25 18:00 (PST is correct in December → CET in Gothenburg)
# No zone = assumed Gothenburg local
to_gbgt "July 11 14:00"
# → 2026-07-11 14:00
# UK time
to_gbgt "July 11 2pm BST"
# → 2026-07-11 15:00 (BST = Europe/London, UTC+1 in summer → UTC+2 in Gothenburg)
# Explicit IANA zone as second arg
to_gbgt "Tomorrow 9am" Asia/Tokyo
# → 02:00 (JST = UTC+9 → CEST = UTC+2, 7h behind)| Abbreviation(s) | Maps to | Notes |
|---|---|---|
| EST, EDT, ET, Eastern | America/New_York | DST handled automatically |
| CST, CDT, CT, Central | America/Chicago | Not China Standard Time |
| MST, MDT, MT, Mountain | America/Denver | |
| PST, PDT, PT, Pacific | America/Los_Angeles | |
| GMT, UTC, Z | UTC | |
| CET, CEST | Europe/Stockholm | |
| BST | Europe/London | British Summer Time, not Bangladesh |
Any IANA timezone name (e.g. Asia/Tokyo, Australia/Sydney) can also be passed directly as the second argument and will be used as-is.
Every existing web tool either (a) parses natural language but doesn't convert timezones (Chrono, Duckling), or (b) converts timezones but expects structured input (timeanddate.com). No free service does both in one step. Meanwhile, GNU date already ships with every Linux system and handles natural-language parsing natively via -d. The only missing piece was the timezone abbreviation logic — which is trivially solved in Bash.
Timezone abbreviations like "EST" carry no DST metadata. They are fixed offsets masquerading as geographic identifiers. The IANA timezone database (via America/New_York) encodes the full history and rules of DST transitions. By mapping "EST" → America/New_York, the function lets the system determine whether EDT applies at the given date, rather than blindly applying UTC−5.
This is the single most important design decision in the script. Without it, summer times are silently wrong by one hour.
If the abbreviation remains in the string passed to date -d, GNU date will interpret it as a fixed UTC offset and adjust accordingly — overriding any TZ environment variable. By stripping the abbreviation before parsing, we ensure that TZ controls the interpretation, and the IANA zone handles DST correctly.
Gothenburg shares the timezone with Stockholm (they are in the same IANA zone: Europe/Stockholm). The script was built for a Gothenburg-based user. If you need a different target timezone, change the TZ="Europe/Stockholm" assignments to your preferred zone, or parameterise it.
ISO 8601 permits several formats. The full canonical form includes the T separator and offset (2026-07-11T20:00:00+02:00). For human reading, this is noise. The script outputs the date-time portion in ISO 8601 calendar format without the separator or offset — unambiguous, sortable, and clean. If you need the full form, swap "+%Y-%m-%d %H:%M" for --iso-8601=seconds.
date and sed are everywhere on Linux. No Python, no Node.js, no API keys, no network calls. The function works offline, in a TTY, over SSH, in a container — anywhere a Bash shell exists.
- GNU
coreutils(datewith-dsupport) sed(GNU or BSD — the regex is POSIX-compatible)- Bash 4.0+ (for
${var^^}, though atrfallback is trivial to add)
Not tested on macOS. BSD date does not support -d for natural language parsing. Install coreutils via Homebrew (gdate) if needed.
- Abbreviation ambiguity. "CST" could be US Central, China Standard, or Cuba Standard. The script assumes US Central. There is no way to disambiguate from context in a single-argument function.
- No multi-zone strings. The function finds one timezone abbreviation. Expressions containing multiple time references are not supported.
- GNU
dateparsing limits. Ifdate -dcan't parse the stripped string, the function falls back to UTC and may produce unexpected results. Exotic date phrasings may fail silently. - Two-digit years. GNU
dateinterprets 2-digit years using a sliding window. Always provide 4-digit years for safety.
Affero GPL. Because if it runs on your system, you should be able to read, modify, and share it.
Built with Lumo, Proton's AI assistant. The natural-language parsing capability is entirely GNU date's — Lumo just connected the dots and wrote the glue.