如何使用 Postgresql 19 和时间 0.3 从 Rust 中的 TIMESTAMPTZ 值获取 UTC 偏移量?

问题描述 投票:0回答:1

我正在尝试使用 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() 的适当值,我如何正确显示当地时间?

postgresql rust time timezone
1个回答
0
投票

DIY

postgres

文档有些误导。 “支持
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
选项
您可以从这里做什么:

要求 PostgreSQL 服务为每个值

提供时区偏移量
  • select extract(timezone from $1)。当您不一次查询大量值时,这可能是可以接受的。但更好的解决方案是: 重构您的代码并将时间替换为
    chrono
  • jiff
  • 。这两个包都支持通过 IANA 数据库的时区,将 UTC 值转换为应用程序的本地时间。代码库会更大,但性能会更好。
    
        
    	
© www.soinside.com 2019 - 2024. All rights reserved.