如何从UTC日期、时间字符串与时区构建chrono::DateTime对象?
如何将日期、时间与时区组合为
chrono::DateTime对象 给定以下输入:
- time =
18:00 - timezone =
Europe/London(或类似格式如Europe__London、Europe.London,可按需修改格式) - 日期:从
chrono::Utc::now()提取的日期字段
需要将这些数据组合为chrono::DateTime对象。我想到两种思路,但都遇到了卡点:
- 构造RFC3339格式字符串再解析:方法简单但低效繁琐,且不知道如何将
chrono_tz::Tz对象根据日期转换为RFC3339需要的小时偏移量。 - 直接操作chrono类型构建对象:已能构造
Tz对象,但不清楚如何用它结合日期、时间来构建DateTime,也不确定FixedOffset是否是正确的类型。
我的尝试
方案1:字符串处理
尝试构造RFC3339字符串再解析:
let datetime_rfc3339_format_string = format!("{}T{}-{}", date_string, time_string, timezone_string); let datetime_remote = chrono::DateTime::parse_from_rfc3339(datetime_remote_rfc3339_format);
但卡在时区字符串转换上:已能通过Tz::from_str构造chrono_tz::Tz对象,但不知道如何根据当前日期将其转为RFC3339需要的小时偏移量。
日期和时间部分已解决:
// 日期字符串 let datetime = chrono::Utc::now(); let date = datetime.date_naive(); let string_date = format!("{}", date); // 时间字符串已从文件读取为符合格式的字符串(如`08:00`)
方案2:直接操作chrono类型
已构造Tz对象:
let chrono_timezone = Tz::from_str(timezone.as_str()) .expect("failed to convert string to chrono tz");
但不清楚如何用这个时区对象,结合已有日期和时间来构建DateTime,也不确定FixedOffset是否适用,以及它和Tz的关联。
解决方案
优先方案:直接通过chrono_tz::Tz构建DateTime
chrono_tz::Tz实现了chrono::offset::TimeZone trait,可直接用该trait的方法构建带时区的DateTime对象,无需绕字符串解析,是最高效的方式。
具体步骤:
- 从
Utc::now()提取日期的年、月、日数值; - 解析时间字符串得到时、分、秒(默认秒为0);
- 调用
Tz的with_ymd_and_hms方法构建DateTime<Tz>,按需转换为其他时区(如UTC)。
示例代码:
use chrono::{NaiveDate, NaiveTime, Utc}; use chrono_tz::Tz; fn main() { // 输入数据 let time_str = "18:00"; let timezone_str = "Europe/London"; let utc_now = Utc::now(); let date = utc_now.date_naive(); // 获取本地日期对象 // 解析时间为NaiveTime let naive_time = NaiveTime::parse_from_str(time_str, "%H:%M") .expect("Failed to parse time string"); // 解析时区为Tz let tz = Tz::from_str(timezone_str) .expect("Failed to parse timezone string"); // 构建带时区的DateTime let datetime_with_tz = tz.with_ymd_and_hms( date.year(), date.month(), date.day(), naive_time.hour(), naive_time.minute(), naive_time.second() ).expect("Failed to construct DateTime"); // 可选:转换为UTC时间 let datetime_utc = datetime_with_tz.with_timezone(&Utc); println!("带时区的时间: {}", datetime_with_tz); println!("UTC时间: {}", datetime_utc); }
方案1的补充(若需使用)
如果一定要用RFC3339字符串解析,无需手动拼接,可先构建带时区的DateTime再生成标准字符串:
// 先按方案2构建datetime_with_tz let rfc3339_str = datetime_with_tz.to_rfc3339(); let parsed_datetime = chrono::DateTime::parse_from_rfc3339(&rfc3339_str) .expect("Failed to parse RFC3339 string");
若要手动拼接偏移量,需先获取对应日期下时区的动态偏移:
// 获取该日期下时区的偏移量(处理夏令时等规则) let offset = tz.offset_from_local_date(&date) .next() // 处理可能的歧义(如夏令时切换时刻) .expect("Failed to get offset for date"); // 格式化为RFC3339要求的偏移格式(如+01:00或Z) let offset_str = format!("{:+03}:{:02}", offset.local_minus_utc() / 3600, (offset.local_minus_utc() % 3600) / 60);
但这种方式仍不如直接构建DateTime高效。
关于FixedOffset和Tz的区别
FixedOffset表示固定的UTC偏移量(如+08:00),不会随日期时间变化;Tz表示包含夏令时、时区规则的完整时区(如Europe/London),会根据日期自动调整偏移量。
如果你的时区需要处理夏令时等动态规则,必须使用Tz,不能用FixedOffset。
内容的提问来源于stack exchange,提问作者user2138149
相关产品推荐
相关产品推荐

