我想防止在 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/