EventNotifier should show dates/times in the client's timezone
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generates configs/eventnotifier_timezones.cfg from the system tzdata.
|
||||
|
||||
Each zone lists "<utc timestamp>" "<offset seconds> <abbreviation>" pairs; the
|
||||
"0" entry is the offset in effect before the first transition in range.
|
||||
Regenerate before END_YEAR runs out (32-bit timestamps end in 2038 anyway).
|
||||
"""
|
||||
|
||||
import re
|
||||
import zoneinfo
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
|
||||
START_YEAR = 2025
|
||||
END_YEAR = 2037
|
||||
|
||||
OUT = Path(__file__).resolve().parent.parent / "configs" / "eventnotifier_timezones.cfg"
|
||||
|
||||
|
||||
def utc(ts):
|
||||
return datetime.fromtimestamp(ts, timezone.utc)
|
||||
|
||||
|
||||
def state(zone, ts):
|
||||
local = utc(ts).astimezone(zone)
|
||||
return int(local.utcoffset().total_seconds()), local.tzname()
|
||||
|
||||
|
||||
def abbreviation(name, offset):
|
||||
# tzdata uses numeric names like "+03" / "-0330" for zones without a real abbreviation.
|
||||
if name and re.fullmatch(r"[A-Za-z]+", name):
|
||||
return name
|
||||
sign = "+" if offset >= 0 else "-"
|
||||
hours, rem = divmod(abs(offset), 3600)
|
||||
minutes = rem // 60
|
||||
if hours == 0 and minutes == 0:
|
||||
return "UTC"
|
||||
return f"UTC{sign}{hours}:{minutes:02d}" if minutes else f"UTC{sign}{hours}"
|
||||
|
||||
|
||||
def transitions(zone):
|
||||
start = int(datetime(START_YEAR, 1, 1, tzinfo=timezone.utc).timestamp())
|
||||
end = int(datetime(END_YEAR, 12, 31, tzinfo=timezone.utc).timestamp())
|
||||
step = int(timedelta(days=1).total_seconds())
|
||||
|
||||
periods = [(0, *state(zone, start))]
|
||||
prev_ts, prev = start, periods[0][1:]
|
||||
ts = start + step
|
||||
while ts <= end:
|
||||
cur = state(zone, ts)
|
||||
if cur != prev:
|
||||
# Bisect to the first second of the new state.
|
||||
lo, hi = prev_ts, ts
|
||||
while hi - lo > 1:
|
||||
mid = (lo + hi) // 2
|
||||
if state(zone, mid) == prev:
|
||||
lo = mid
|
||||
else:
|
||||
hi = mid
|
||||
periods.append((hi, *state(zone, hi)))
|
||||
prev = cur
|
||||
prev_ts = ts
|
||||
ts += step
|
||||
return periods
|
||||
|
||||
|
||||
def main():
|
||||
lines = ["// Generated by tools/gen_timezones.py, do not edit by hand.", '"Timezones"', "{"]
|
||||
for name in sorted(zoneinfo.available_timezones()):
|
||||
if name.startswith(("posix/", "right/")) or name in ("Factory", "localtime"):
|
||||
continue
|
||||
zone = zoneinfo.ZoneInfo(name)
|
||||
lines.append(f'\t"{name}"')
|
||||
lines.append("\t{")
|
||||
for ts, offset, tzname in transitions(zone):
|
||||
lines.append(f'\t\t"{ts}"\t"{offset} {abbreviation(tzname, offset)}"')
|
||||
lines.append("\t}")
|
||||
lines.append("}")
|
||||
|
||||
OUT.parent.mkdir(parents=True, exist_ok=True)
|
||||
OUT.write_text("\n".join(lines) + "\n")
|
||||
print(f"Wrote {OUT}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user