# /// script
# requires-python = ">=3.10"
# dependencies = ["python-dateutil"]
# ///
# Copyright (c) 2026 Aayush Sharma · SPDX-License-Identifier: MIT
# https://thedataengineering.com/lab-code/LICENSE.txt
"""The daylight-saving key bug.

26 October 2025, 02:30 in Berlin happens twice. The two instants share the
same local text but are an hour apart, so a key built from local time
collides. Then month arithmetic: 30 January + 1 month + 1 day against
30 January + 1 day + 1 month, with dateutil's month rule.
"""
import argparse, json
from datetime import datetime, date, timedelta
from zoneinfo import ZoneInfo
from dateutil.relativedelta import relativedelta

p = argparse.ArgumentParser(description=__doc__.splitlines()[0])
p.add_argument("--json", help="Also write the results to this JSON file.")
args = p.parse_args()

berlin, utc = ZoneInfo("Europe/Berlin"), ZoneInfo("UTC")
a = datetime(2025, 10, 26, 2, 30, tzinfo=berlin, fold=0); b = datetime(2025, 10, 26, 2, 30, tzinfo=berlin, fold=1)
local = [a.strftime("%Y-%m-%d %H:%M"), b.strftime("%Y-%m-%d %H:%M")]
instants = [a.astimezone(utc).isoformat(), b.astimezone(utc).isoformat()]
d = date(2025, 1, 30)
m_then_d = d + relativedelta(months=1) + timedelta(days=1); d_then_m = d + timedelta(days=1) + relativedelta(months=1)
rows = [{"case": "02:30, first time (fold=0)", "local_text": local[0], "utc": instants[0]},
        {"case": "02:30, second time (fold=1)", "local_text": local[1], "utc": instants[1]}]
summary = {"same_local_text": "yes" if local[0] == local[1] else "no", "hours_apart": (b.astimezone(utc) - a.astimezone(utc)).total_seconds() / 3600,
           "month_then_day": m_then_d.isoformat(), "day_then_month": d_then_m.isoformat()}
for r in rows: print(f"{r['case']:<28} local {r['local_text']}   UTC {r['utc']}")
print(f"same local text: {summary['same_local_text']}; {summary['hours_apart']:.0f} hour apart")
print(f"30 Jan + 1 month + 1 day = {m_then_d}; 30 Jan + 1 day + 1 month = {d_then_m}")

if args.json:
    with open(args.json, "w") as f:
        json.dump({"summary": summary, "tables": {"instants": rows}}, f)
