PostgreSQL:如何测试时间戳是否有时区?

标签 postgresql datetime timezone timestamp-with-timezone

我想防止在 PostgreSQL SQL 函数中插入任何没有时区的时间戳。我设法想出的唯一方法不起作用,因为 Postgres 似乎忽略了任何时区字符串后缀,而是使用服务器的时区:

hostname:~ username$ date
Tue Sep 27 15:30:16 CEST 2016

hostname:~ username$ uname -a
Darwin hostname.domain 14.5.0 Darwin Kernel Version 14.5.0: Mon Aug 29 21:14:16 PDT 2016; root:xnu-2782.50.6~1/RELEASE_X86_64 x86_64

hostname:~ username$ psql -U postgres
psql (9.5.3)
Type "help" for help.

postgres=# SELECT extract(TIMEZONE FROM '2016-09-19 01:00:00'::timestamptz);
 date_part
-----------
      7200
(1 row)

postgres=# SELECT extract(TIMEZONE FROM '2016-09-19 01:00:00+0200'::timestamptz);
 date_part
-----------
      7200
(1 row)

postgres=# SELECT extract(TIMEZONE FROM '2016-09-19 01:00:00+0800'::timestamptz);
 date_part
-----------
      7200
(1 row)

我总觉得自己误解了什么。谁能帮忙?

更新 20160928:

为了给出一些解释性的上下文,这是我的数据库(精简到手头问题的必要内容):

CREATE DATABASE my_db;
CREATE TABLE my_table
(
    id serial PRIMARY KEY,
    timestamp_utc timestamp with time zone NOT NULL,
    title text NOT NULL
);

这是我以当前形式插入数据的函数:

CREATE FUNCTION insert_row
(
    p_timestamp_utc timestamp with time zone,
    p_title         text
)
RETURNS integer
LANGUAGE SQL
SECURITY DEFINER
VOLATILE
AS
$BODY$
    INSERT INTO my_table
                (  timestamp_utc    title)
         VALUES (p_timestamp_utc, p_title)
      RETURNING id;
$BODY$;

我创建了一个 SQLFiddle ;尽管在那里创建函数总是失败...

问题:

即使时间戳参数不带时区,调用函数也会成功:

SELECT insert_row('2016-09-01 01:00:00'::timestamptz, 'some title');

我需要找到一种方法让这个函数调用失败。

为什么我需要让这个失败的原因是我希望通过代码强制定义任何时间戳所在的时区;另一种选择是数据库服务器和客户端都以某种方式隐含地/默默地同意一个约定——这对我来说听起来并不是一个明智的举动……

最佳答案

在 PostgreSQL 中,时区信息不与timestamp with time zone 一起存储。 相反,时间戳被转换为 UTC当它转换为其内部表示时。

timestamp with time zone 被转换为字符串时,例如显示时,它会转换为 TimeZone 配置参数中设置的时区。

当您使用 EXTRACT 检索时区信息时,也会发生同样的情况。文档对此有点不清楚。

因此,如果您的时区设置如下:

test=> SHOW TimeZone;
   TimeZone
---------------
 Europe/Vienna
(1 row)

您将获得:

test=> SELECT extract(TIMEZONE FROM '2016-01-01 00:00:00-07'::timestamptz);
 date_part
-----------
      3600
(1 row)

因为欧洲中部时间与 UTC 相差 1 小时,并且

test=> SELECT extract(TIMEZONE FROM '2016-08-01 00:00:00-07'::timestamptz);
 date_part
-----------
      7200
(1 row)

因为中欧夏令时与 UTC 相差 2 小时

关于PostgreSQL:如何测试时间戳是否有时区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39726097/

相关文章:

ruby-on-rails - 列必须出现在 GROUP BY 子句中或用于聚合函数 Ruby

postgresql - PSQL : Find record where JSONB field with array of hashes contains some case insensitive value

java - Hibernate (JPA) 和 PostgreSQL 的查询问题

ios - MonoTouch DateTime.ToLocalTime 在时区更改时不更新

MySQL - 如何在 INSERT 语句中将字符串值解析为 DATETIME 格式?

postgresql - 如何允许在 Ubuntu 中使用 postgres 访问 CSV 文件的权限

php - 使用 Laravel 插入 created_at 数据

mysql - MySQL 和 MSSQL 服务器上的 UNIX 时间戳

postgresql - 谁负责更新 pg_timezone_names View ?

ios - Swift 获取前几年的日期时间 GMT+08 :00 timezone