|
18 | 18 | //! temporal kernels |
19 | 19 |
|
20 | 20 | use chrono::{ |
21 | | - DateTime, Datelike, Duration, LocalResult, NaiveDate, NaiveDateTime, Offset, TimeZone, |
22 | | - Timelike, Utc, |
| 21 | + DateTime, Datelike, Duration, LocalResult, NaiveDate, NaiveDateTime, TimeZone, Timelike, Utc, |
23 | 22 | }; |
24 | 23 |
|
25 | 24 | use std::sync::Arc; |
@@ -157,29 +156,22 @@ where |
157 | 156 | } |
158 | 157 |
|
159 | 158 | // Apply the Tz to the Naive Date Time, convert to UTC, and return as microseconds in Unix epoch. |
160 | | -// This function re-interprets the local datetime in the timezone to ensure the correct DST offset |
161 | | -// is used for the target date (not the original date's offset). This is important when truncation |
162 | | -// changes the date to a different DST period (e.g., from December/PST to October/PDT). |
163 | | -// |
164 | | -// Note: For far-future dates (approximately beyond year 2100), chrono-tz may not accurately |
165 | | -// calculate DST transitions, which can result in incorrect offsets. See the compatibility |
166 | | -// guide for more information. |
| 159 | +// After truncation the carried UTC offset may be wrong if the truncated time falls in a different |
| 160 | +// DST period than the original (e.g., truncating a December/PST timestamp to QUARTER yields |
| 161 | +// October 1 which is in PDT). We re-resolve the naive local time through the timezone so that |
| 162 | +// chrono picks the correct offset for the target date. |
167 | 163 | #[inline] |
168 | 164 | fn as_micros_from_unix_epoch_utc(dt: Option<DateTime<Tz>>) -> i64 { |
169 | 165 | let dt = dt.unwrap(); |
170 | 166 | let naive = dt.naive_local(); |
171 | 167 | let tz = dt.timezone(); |
172 | 168 |
|
173 | | - // Re-interpret the local time in the timezone to get the correct DST offset |
174 | | - // for the truncated date. Use noon to avoid DST gaps that occur around midnight. |
175 | | - let noon = naive.date().and_hms_opt(12, 0, 0).unwrap_or(naive); |
176 | | - |
177 | | - let offset = match tz.offset_from_local_datetime(&noon) { |
178 | | - LocalResult::Single(off) | LocalResult::Ambiguous(off, _) => off.fix(), |
179 | | - LocalResult::None => return dt.with_timezone(&Utc).timestamp_micros(), |
180 | | - }; |
181 | | - |
182 | | - (naive - offset).and_utc().timestamp_micros() |
| 169 | + match tz.from_local_datetime(&naive) { |
| 170 | + LocalResult::Single(resolved) | LocalResult::Ambiguous(resolved, _) => { |
| 171 | + resolved.with_timezone(&Utc).timestamp_micros() |
| 172 | + } |
| 173 | + LocalResult::None => dt.with_timezone(&Utc).timestamp_micros(), |
| 174 | + } |
183 | 175 | } |
184 | 176 |
|
185 | 177 | #[inline] |
|
0 commit comments