[PG Upgrade Series] Extract Epoch Trap

本文探讨了在从PostgreSQL 9.1升级到11时,从无时区的时间戳中提取Unix时间戳(Epoch)导致不同结果的问题。文章解释了这实际上是由于PostgreSQL从9.2版本开始区分了带时区和不带时区的时间戳,并提供了如何避免陷阱的建议。建议在提取Epoch时使用带时区的时间戳或将其转换为带时区的时间戳。

Background

In many cases applications need to get current Unix timestamp (seconds since 1970-01-01 00:00:00 UTC, also called Unix epoch or Unix time or POSIX time) as the following Linux command shows.

# date -d '2020-01-01' +%s
1577808000

The Extract Epoch Issue

After upgrading PostgreSQL 9.1 to PostgreSQL 11, the same SQL produces different results.

SELECT extract(epoch from '2020-01-01 00:00:00'::timestamp without time zone);

In PostgreSQL 9.1,

postgres=# SELECT version();
                                                    version
------------------------------------------------------------------------------------------------
 PostgreSQL 9.1.x on xxx
(1 row)
postgres=# SELECT extract(epoch from '2020-01-01 00:00:00'::timestamp without time zone);
 date_part  
------------
 1577808000
(1 row)
postgres=# SELECT to_timestamp(extract(epoch from '2020-01-01 00:00:00'::timestamp without time zone));
      to_timestamp      
------------------------
 2020-01-01 00:00:00+08
(1 row)

However in PostgreSQL 11, the outcome is NOT same !

postgres=# SELECT version();
                                                    version
------------------------------------------------------------------------------------------------
 PostgreSQL 11.x on xxx
(1 row)
postgres=# SELECT extract(epoch from '2020-01-01 00:00:00'::timestamp without time zone);
 date_part  
------------
 1577836800
(1 row)
postgres=# SELECT to_timestamp(extract(epoch from '2020-01-01 00:00:00'::timestamp without time zone));
      to_timestamp      
------------------------
 2020-01-01 08:00:00+08
(1 row)

Bug or Feature

After exploring PostgreSQL 9.1 and PostgreSQL 9.2 documentations, we can get some clues.

PostgreSQL 9.1 EXTRACT

epoch

For date and timestamp values, the number of seconds since 1970-01-01 00:00:00 UTC (can be negative); for interval values, the total number of seconds in the interval

PostgreSQL 9.2 EXTRACT

epoch

For timestamp with time zone values, the number of seconds since 1970-01-01 00:00:00 UTC (can be negative); for date and timestamp values, the number of seconds since 1970-01-01 00:00:00 local time; for interval values, the total number of seconds in the interval

As you can see, starting from PostgreSQL 9.2, it distinguishes between timestamp without time zone and timestamp with time zone, while PostgreSQL 9.1 not.

It makes sense as epoch is the seconds since 1970-01-01 00:00:00 UTC which is a timestamp with time zone.

When extracting epoch from a timestamp without time zone, strictly speaking, it should not use the word ‘epoch’ which always relates to UTC time zone.

Say, when extracting seconds from a timestamp without time zone, it will return the number of seconds since 1970-01-01 00:00:00 local time

Let’s try to explain the weird result in PostgreSQL 11 when extracting seconds from a timestamp without time zone based on the documentation.

As shown below, the offset is 28800 seconds, i.e. 8 hours, which is exactly the same utc_offset of the local time zone PRC.

postgres=# SELECT version();
                                                  
pg_upgradePostgreSQL 提供的一个用于升级数据库集群的工具,通常与 PostgreSQL 的安装包一起发布。要下载 `pg_upgrade` 工具,需要下载对应版本的 PostgreSQL 安装包,并在其二进制目录中找到 `pg_upgrade`。 ### 获取 pg_upgrade 的方式 1. **通过安装完整的 PostgreSQL 套件获取** `pg_upgrade` 作为 PostgreSQL 的一部分,包含在官方发布的各个版本中。可以通过访问 PostgreSQL 官方网站 [https://www.postgresql.org/download/](https://www.postgresql.org/download/) 下载所需版本的 PostgreSQL 安装包(如 Linux 的 RPM 或 DEB 包、Windows 的安装程序等)[^1]。 2. **使用源码编译安装** 如果希望手动控制构建过程,可以从 PostgreSQL 官方获取源码并进行编译: ```bash # 下载源码 wget https://ftp.postgresql.org/pub/source/v13.4/postgresql-13.4.tar.gz tar -zxvf postgresql-13.4.tar.gz cd postgresql-13.4 # 编译安装 ./configure make sudo make install ``` 编译完成后,在 `/usr/local/pgsql/bin/` 目录下即可找到 `pg_upgrade` 可执行文件[^1]。 3. **通过系统包管理器安装** 在 Linux 系统上,可以使用包管理器来安装 PostgreSQL 及其配套工具,例如: - **Debian/Ubuntu**: ```bash sudo apt-get install postgresql postgresql-client postgresql-contrib ``` - **Red Hat/CentOS**: ```bash sudo yum install postgresql-server postgresql-contrib ``` 安装完成后,`pg_upgrade` 将位于 PostgreSQL 的二进制目录中(如 `/usr/pgsql-10/bin/pg_upgrade`)。 ### 注意事项 - **版本兼容性**:确保下载的 `pg_upgrade` 版本与当前运行的 PostgreSQL 版本兼容。例如,如果正在从 PostgreSQL 9.6 升级到 10,则应使用 PostgreSQL 10 版本中的 `pg_upgrade` 工具[^1]。 - **测试环境验证**:在生产环境中使用前,建议先在测试环境中验证升级流程,以避免数据丢失或服务中断。 ### 示例命令 以下是一个典型的 `pg_upgrade` 使用示例: ```bash /usr/pgsql-10/bin/pg_upgrade \ -b /usr/pgsql-9.6/bin \ -B /usr/pgsql-10/bin \ -d /var/lib/pgsql/9.6/data \ -D /var/lib/pgsql/10/data \ -p 5434 \ -P 5432 \ -U postgres ``` 此命令将 PostgreSQL 9.6 的数据库实例升级到 10 版本,其中 `-b` 和 `-B` 分别指定旧版和新版 PostgreSQL 的二进制路径,`-d` 和 `-D` 指定旧版和新版的数据目录,`-p` 和 `-P` 表示旧版和新版的端口号。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值