You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL二进制Timestamp解析异常:最小值转换错误求助

PostgreSQL二进制timestamp格式解析问题

我尝试解析PQGetValue返回的PostgreSQL二进制格式timestamp值,通过以下C函数将其转换为struct tm:

#define PG_EPOCH_TIME_T   946681200 // pg epoch in unix epoch
static inline int _convert_pg_timestamp_to_tm( struct tm* _tm, uint64_t pg_timestamp )
{
    int64_t i;
    struct tm tm;
    struct tm* p;
    uint64_t u;

    u = be64toh(pg_timestamp);
    memcpy( &i, &u, sizeof(uint64_t) );

    i /= 1000000;
    i += PG_EPOCH_TIME_T;


//    p = gmtime_r( &i, &tm );
    p = localtime_r( &i, &tm );
    if( p != &tm )
        return -1;
    dump_tm( &tm );

    memset( _tm, 0, sizeof(struct tm) );

    _tm->tm_year = tm.tm_year;
    _tm->tm_mon = tm.tm_mon;
    _tm->tm_mday = tm.tm_mday;

    _tm->tm_hour = tm.tm_hour;
    _tm->tm_min = tm.tm_min;
    _tm->tm_sec = tm.tm_sec;

    dump_tm( _tm );

    return 0;
}

公元(AD)时间转换正常,但转换timestamp最小值4713-01-01 00:00:00 BC时,得到错误结果:Wed Dec 31 23:09:21 -4713。

我怀疑这个8字节值不只是相对于PostgreSQL纪元的微秒数,可能存在用于其他用途的位或字节。另外带时区的timestamp类型拥有相同范围和数据长度,说明有预留空间,数据并非单纯偏移量。我未找到说明其底层结构的文档,特此求助:这个8字节数据的底层结构是什么?


问题解答

PostgreSQL的timestamp(不带时区)和timestamptz(带时区)二进制存储格式本质是带符号64位整数,单位为微秒,基准是PostgreSQL内部纪元:2000-01-01 00:00:00 UTC。

错误原因分析

你遇到的BC时间转换错误,并非存储格式有额外位,核心原因有两点:

  1. time_t范围限制:标准time_t即便为64位,其可表示的最早时间也远晚于4713 BC,localtime_r/gmtime_r无法正确解析超出范围的时间值,导致出现异常偏移。
  2. 纪元转换后的溢出问题:PostgreSQL timestamp最小值4713-01-01 BC对应的微秒数为-63082281600000000(相对于2000-01-01 UTC),转换为time_t后完全超出其有效范围,触发标准时间函数的解析错误。

正确处理方向

若要支持PostgreSQL timestamp的完整范围(4713 BC 至 294276 AD),不能依赖time_t和标准C时间函数,需自行实现日期时间的加减与解析逻辑;或在客户端通过调用PostgreSQL的to_char函数将timestamp转换为字符串后再解析(此方法效率较低)。

补充说明

timestamptz与timestamp存储长度相同,是因为两者都采用64位带符号微秒数的结构:timestamptz存储的是转换为UTC后的时间微秒数,timestamp存储的是本地时间微秒数,并无预留空间,只是语义不同。


内容的提问来源于stack exchange,提问作者mystackoverflowpseudo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 02:02:14