diff --git a/bal/gui/qt/widgets.py b/bal/gui/qt/widgets.py index 3a181b9..1c1deb7 100644 --- a/bal/gui/qt/widgets.py +++ b/bal/gui/qt/widgets.py @@ -612,9 +612,14 @@ class LockTimeDateEdit(QDateTimeEdit, _LockTimeEditor): # Use the overflow-safe converter: on Windows datetime.fromtimestamp # raises OverflowError for timestamps past 2038 (e.g. NLOCKTIME_MAX). _dt = BalTimestamp._safe_fromtimestamp(x) - #if self.alarm != dt: - self.setDateTime(_dt) self.alarm = _dt + # Store the LOCAL wall-clock time, not the aware-UTC datetime: + # QDateTimeEdit keeps the given wall time with a LocalTime spec, so + # an aware-UTC datetime would make get_value() read back a timezone- + # shifted epoch. That broke the set_value -> get_value roundtrip and + # kept the valueEdited -> update_setting_widgets -> set_value cycle + # firing forever (infinite RecursionError on wizard "Next"). + self.setDateTime(_dt.astimezone().replace(tzinfo=None)) diff --git a/tests/test_gui_widgets.py b/tests/test_gui_widgets.py index b6a71de..8a4dd73 100644 --- a/tests/test_gui_widgets.py +++ b/tests/test_gui_widgets.py @@ -183,6 +183,22 @@ def test_locktime_raw_edit_get_set_value(): assert "d" in val +def test_locktime_date_edit_get_set_value_roundtrip(): + """set_value(x) must roundtrip to get_value() == x (same timezone). + + Guards a timezone regression that made the Date editor return the stored + wall clock re-read as local time, i.e. ``x + utc_offset``. That broke the + set_value/get_value roundtrip and kept the valueEdited -> + update_setting_widgets -> set_value signal cycle alive forever, ending in a + RecursionError when opening the "Build your will" wizard (Next button). + """ + from bal.gui.qt.widgets import LockTimeDateEdit + edit = LockTimeDateEdit() + for ts in (1700000000, 1750000000, 2147483647): + edit.set_value(ts) + assert edit.get_value() == ts + + # ------------------------------------------------------------------ # # PercAmountEdit # ------------------------------------------------------------------ #