如何在Rust中使用postgres-rs结合time-rs 0.3显示本地时区的TIMESTAMPTZ
问题:postgres-rs + time-rs 0.3 无法正确获取带时区修正的本地时间
问题场景
在Rust中使用postgres-rs结合time-rs 0.3(替代chrono-rs 0.4)获取本地时间时,数据库时区设置为Europe/Amsterdam,但拿到的是未做时区修正的UTC时间。
在psql中执行:
show timezone; select now();
返回结果:
Europe/Amsterdam 2024-10-01 10:38:36.63829+02
但Rust代码运行后输出不符合预期:
// mut conn: PooledConnection<PostgresConnectionManager<MakeTlsConnector>> let mut tz: Option<String> = None; if let Ok(r) = conn.query_one("show timezone", &[]) { tz = r.get(0); } println!("timezone: {:?}", tz); let mut now: Option<OffsetDateTime> = None; if let Ok(r) = conn.query_one("select now()", &[]) { now = r.get(0); } println!("now: {:?}", now);
输出:
timezone: Some("Europe/Amsterdam") now: Some(2024-10-01 8:41:49.767418 +00:00:00)
需要解决的核心问题:无法从OffsetDateTime.offset()获取合适偏移值时,如何正确显示本地时间?
解决方案
1. 启用time-rs的时区数据库特性
PostgreSQL的timestamptz类型内部以UTC存储,postgres-rs会直接解析为UTC偏移的OffsetDateTime。要转换为目标时区,需先启用time-rs的tzdb特性来解析时区字符串。
修改Cargo.toml:
time = { version = "0.3", features = ["tzdb", "formatting"] }
2. 手动转换UTC时间到目标时区
先获取数据库时区并解析为time-rs的Tz类型,再将UTC时间转换为对应时区的本地时间:
use time::{OffsetDateTime, Tz}; use postgres::error::Error; fn get_local_time(conn: &mut PooledConnection<PostgresConnectionManager<MakeTlsConnector>>) -> Result<(), Error> { // 获取数据库时区字符串并解析为Tz类型 let tz_str: String = conn.query_one("show timezone", &[])?.get(0); let tz = Tz::try_from(tz_str.as_str()).expect("无效的时区字符串"); // 获取UTC时间 let utc_now: OffsetDateTime = conn.query_one("select now()", &[])?.get(0); // 转换为目标时区的OffsetDateTime(带偏移信息) let local_offset_time = utc_now.to_offset(tz); // 或转换为本地时间(不带偏移的PrimitiveDateTime) let local_primitive_time = utc_now.to_offset(tz).date_time(); println!("UTC时间: {:?}", utc_now); println!("阿姆斯特丹时区时间: {:?}", local_offset_time); println!("阿姆斯特丹本地时间: {:?}", local_primitive_time); // 格式化显示示例 println!("格式化本地时间: {}", local_offset_time.format("%Y-%m-%d %H:%M:%S %z")); Ok(()) }
3. 关键原理说明
PostgreSQL的now()返回的timestamptz在传输给客户端时会转为UTC,postgres-rs的time-rs绑定直接解析为UTC偏移的OffsetDateTime。要得到数据库时区对应的本地时间,必须手动完成UTC到目标时区的偏移转换,这依赖time-rs的时区数据库来解析Europe/Amsterdam这类时区标识。
内容的提问来源于stack exchange,提问作者Code4R7
相关产品推荐
相关产品推荐

