我正在尝试使用 postgres crate 显示本地时间,使用时间 0.3 而不是 chrono。但将时区设置为“欧洲/阿姆斯特丹”时,我得到的只是 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() 的适当值,我如何正确显示当地时间?
TIMESTAMPTZ
”实际上意味着数据最初读取为UTC,因为与psql
不同,在您的情况下没有时区支持。
从 UTC 到本地时区的转换必须由客户端完成,因此
postgres
箱将转换委托给您使用的数据类型。由于 time
板条箱不支持时区,因此您必须自己进行转换。
PostgreSQL 对“带时区”的时间戳有意见:
TIMESTAMP
:是UTC时间戳,TIMESTAMPTZ
:也是UTC格式的时间戳,添加一个标志“以你当地时间解析并显示”当您在
TIMESTAMPTZ
中查询 psql
时,会使用会话的 TIMEZONE
设置自动完成转换。
但是,即使您在 Rust 发起的会话中手动设置
TIMEZONE
,TIMESTAMPTZ
二进制值仍然会以 UTC 格式返回。 不提供时区偏移。我不知道为什么,因为数据库服务可能已经考虑到了它。但这会将数据类型更改为“具有实际时区偏移的时间戳”。也许 psql
会正常进行转换,当您假设任何客户端本身负责处理时区而不是 PostgreSQL 服务时,这是有意义的。
另一方面,我不知道为什么
extract(timezone from ..)
存在并在数据库服务中工作。数据库服务在进行日期时间计算时确实需要考虑时区,那么为什么不通过连接的会话提供数据呢?
也许它写在 PostgreSQL 后端协议的某个地方,但我还没有找到。
无论如何,
postgres
板条箱仅接收 UTC 格式的 TIMESTAMPTZ
值。它将转换委托给您的数据类型,并使用您选择的当地时间。但就您而言, time
板条箱根本不支持时区。 FromSql
特性仅返回 Ok(primitive.assume_utc())
,请参阅 here。选项 您可以从这里做什么:
select extract(timezone from $1)
。当您不一次查询大量值时,这可能是可以接受的。但更好的解决方案是:
重构您的代码并将时间替换为 chrono
或 jiff