Skip to content

Commit c792af4

Browse files
committed
improved timezone calculations
1 parent 3cb5b08 commit c792af4

1 file changed

Lines changed: 45 additions & 4 deletions

File tree

src/chuk_mcp_time/timezone_utils.py

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def find_timezone_transitions(
7272
"""
7373
transitions = []
7474

75-
# Sample monthly to detect transitions
75+
# Sample daily to detect transition windows
7676
current = start_dt
7777
prev_info = None
7878

@@ -84,22 +84,63 @@ def find_timezone_transitions(
8484
info["utc_offset_seconds"] != prev_info["utc_offset_seconds"]
8585
or info["is_dst"] != prev_info["is_dst"]
8686
):
87-
# Transition detected, add it
87+
# Transition detected between prev_time and current
88+
# Use binary search to find exact transition time (within 1 minute)
89+
prev_time = current - timedelta(days=1)
90+
transition_time = _find_exact_transition(tz_name, prev_time, current, prev_info, info)
91+
8892
transitions.append(
8993
{
90-
"from_datetime": current.isoformat(),
94+
"from_datetime": transition_time.isoformat(),
9195
"utc_offset_seconds": info["utc_offset_seconds"],
9296
"is_dst": info["is_dst"],
9397
"abbreviation": info["abbreviation"],
9498
}
9599
)
96100

97101
prev_info = info
98-
current += timedelta(days=30) # Sample monthly
102+
current += timedelta(days=1) # Sample daily
99103

100104
return transitions
101105

102106

107+
def _find_exact_transition(
108+
tz_name: str,
109+
start: datetime,
110+
end: datetime,
111+
prev_info: dict[str, str | int | bool],
112+
new_info: dict[str, str | int | bool],
113+
) -> datetime:
114+
"""Binary search to find exact transition time within a window.
115+
116+
Args:
117+
tz_name: IANA timezone identifier
118+
start: Start of window (before transition)
119+
end: End of window (after transition)
120+
prev_info: Timezone info before transition
121+
new_info: Timezone info after transition
122+
123+
Returns:
124+
Datetime of transition (accurate to ~1 minute)
125+
"""
126+
# Binary search with 1-minute precision
127+
while (end - start).total_seconds() > 60:
128+
mid = start + (end - start) / 2
129+
mid_info = get_timezone_info_at_datetime(tz_name, mid)
130+
131+
if (
132+
mid_info["utc_offset_seconds"] == prev_info["utc_offset_seconds"]
133+
and mid_info["is_dst"] == prev_info["is_dst"]
134+
):
135+
# Still in old state, transition is after mid
136+
start = mid
137+
else:
138+
# In new state, transition is before mid
139+
end = mid
140+
141+
return end
142+
143+
103144
def list_all_timezones(
104145
country_code: str | None = None, search: str | None = None
105146
) -> list[dict[str, str | None]]:

0 commit comments

Comments
 (0)