数据类型“带时区的时间戳”中的时区存储

Posted

技术标签:

【中文标题】数据类型“带时区的时间戳”中的时区存储【英文标题】:Time zone storage in data type "timestamp with time zone" 【发布时间】:2015-05-06 12:31:29 【问题描述】:

在 PostgreSQL 中,数据类型 timestamptimestamp with timezone 都使用 8 个字节。

我的问题是:

    时间戳中使用什么格式存储日期和时间? timestamp with timezone中的时区信息是如何存储的 类型,后面读取类型时如何解析?

【问题讨论】:

timestamp.c 【参考方案1】:

这只是源于有点误导的类型名称的误解。时区本身根本不存储。它只是用作计算实际存储的 UTC 时间戳(输入)的偏移量。或者作为根据current 或given 时区显示时间戳的装饰器(输出)。这一切都符合 SQL 标准。

只存储时间点,没有区域信息。这就是为什么 64 位信息就足够了。时间戳根据会话当前的时区设置显示给客户端。

详情:

Ignoring time zones altogether in Rails and PostgreSQL

另外,既然 Jon 提到了,time with time zone 是在 SQL 标准中定义的,因此在 Postgres 中实现,but its use is discouraged:

time with time zone是SQL标准定义的,但是定义 表现出导致有用性受到质疑的特性。

这是一种固有的模棱两可的类型,无法正确处理DST。

【讨论】:

哎呀,这是可怕的误导。感谢您纠正我的误解。 @ErwinBrandstetter 新问题在这里:***.com/questions/28877366/…【参考方案2】:

看着documentation:

时间戳存储为整数或(不推荐使用的)浮点数 我不相信timestamp with timezone 可以在 8 个字节内正确编码,如果它实际上存储了一个时区。只是时间戳需要 64 位,因为 log2(298989 * 365 * 24 * 60 * 60 * 1000000) 大于 63。注意 time with time zone 需要 12 个字节,具有相同的精度,但范围为一天。

请参阅 Erwin 的回答以解释它实际上是如何设法存储在 8 个字节中的——它应该被称为“没有时区的时间戳,但存储在 UTC 中并转换为本地时区以进行显示”。艾克。

【讨论】:

嗨,pg 9.3 doc chp 8.5有一个表,它显示timestamp with timezone只使用8字节,因为它的范围从4713 BC294276 AD,所以它不需要8个字节来存储日期和时间,因此有剩余的时区信息位,但仍然想知道时区是如何存储和解析的。 @Eric:我知道它声称它只需要 8 个字节,但是您如何期望它在不超过 8 个字节的情况下覆盖到微秒精度的年份范围,而忽略时区?这就是我回答中计算的重点 - 表明该范围/精度组合需要 8 个字节。 我认为诀窍在于值的范围,有限的范围减少了存储值所需的位,同时仍保持精度,我猜这是一种数学问题,如您所见time with timezone 需要 12 个字节,因为它的范围更广。但这不是我关心的 :) 我希望了解时区存储和解析部分。 @EricWang:“有限范围”是什么意思? 4713BC 到 294276AD 是 298989 年。这可能time 的范围更广,time一天 内的时间,但精度如何?在我的世界里,298989 年的范围比 1 天要宽 :) 如果您能解释 为什么 您需要知道精确的存储格式,这也会有所帮助。这只是好奇吗?您永远不需要自己处理原始存储格式。 这里房间里的大象是:时区根本没有存储。

以上是关于数据类型“带时区的时间戳”中的时区存储的主要内容,如果未能解决你的问题,请参考以下文章

在 Postgres 中创建表时将空列设置为带时区的时间戳

使用带时区的时间戳提取日期

Apollo/GraphQL:用于时间戳的字段类型?

JPQL 和带时区的时间戳

在 Athena 上转换为带时区的时间戳失败

DateTime<Utc> 编译但不是 DateTime<Local> 查询表,其列定义为带时区的时间戳