如何将chrono-tz中的无效本地时间向前滚动至下一个有效时间?
处理夏令时导致的无效本地时间滚动问题
先看你的代码和问题场景:
Cargo.toml
[package] name = "tmp" version = "0.1.0" edition = "2021" [dependencies] chrono = "0.4.31" chrono-tz = "0.8.3"
src/main.rs
use chrono::{NaiveDateTime, TimeZone}; use chrono_tz::Europe::London; fn main() { let dt = NaiveDateTime::parse_from_str("2020-03-29T01:00:00", "%Y-%m-%dT%H:%M:%S").unwrap(); let dt = London.from_local_datetime(&dt); println!("res: {:?}", dt); }
运行cargo run后输出:
res: None
因为夏令时调整,2020-03-29T01:00:00属于Europe/London时区的无效时间,需要将其滚动到下一个有效时间,且不能硬编码增加1小时(需适配如Lord Howe这类调整半小时的时区)。
半小时递增查找方案的可行性
这个方案完全可行,目前全球时区的夏令时调整最小单位就是30分钟,不存在更小的调整粒度,所以每次递增30分钟循环查找,总能找到下一个有效时间,同时能覆盖所有特殊时区和日历变更导致的长时间无效场景。
实现代码示例
修改你的代码,添加一个通用函数来查找下一个有效时间:
use chrono::{Duration, NaiveDateTime, TimeZone}; use chrono_tz::Europe::London; fn find_next_valid<T: TimeZone>(tz: T, mut local_dt: T::NaiveDateTime) -> T::DateTime { loop { match tz.from_local_datetime(&local_dt) { Some(valid_dt) => return valid_dt, None => local_dt += Duration::minutes(30), } } } fn main() { let dt = NaiveDateTime::parse_from_str("2020-03-29T01:00:00", "%Y-%m-%dT%H:%M:%S").unwrap(); let valid_dt = find_next_valid(London, dt); println!("res: {:?}", valid_dt); }
运行后会输出London时区的下一个有效时间:2020-03-29T02:00:00+01:00(夏令时生效后的时间)。
更高效的优化方案
如果追求更高效率,不想循环递增,可以直接获取目标时区在对应日期的时区转换事件,找到第一个晚于无效时间的转换点,直接跳转到转换后的有效时间。不过这个逻辑需要处理时区的规则数据,实现起来稍复杂,对于大部分场景,半小时递增的方案已经足够简单可靠。
内容的提问来源于stack exchange,提问作者ignoring_gravity
相关产品推荐
相关产品推荐

