我想简单地使用格式为"+hh:mm"(或"-hh:mm")的字符串。这既必要又充分吗?
注意:我不需要存储日期或时间,只需要存储时区。
遗憾的是,PostgreSQL没有提供时区数据类型,因此您可能应该使用text
。
乍一看,interval
似乎是一个合乎逻辑的选项,它适合某些用途。然而,它没有考虑夏令时,也没有考虑同一UTC偏移中的不同地区具有不同的夏令时规则这一事实。
没有从UTC偏移量到时区的1:1映射。
例如,在夏令时期间,Australia/Sydney
(新南威尔士州)的时区为UTC+10
(EST
)或UTC+11
(EDT
)。是的,这与美国使用的缩写词EST
相同;时区首字母缩略词在tzdata数据库中是不唯一的,这就是为什么Pg具有timezone_abbreviations
设置的原因。更糟糕的是,布里斯班(昆士兰)的长度几乎相同,处于UTC+10 EST
。。。但没有夏令时,所以有时在新南威尔士州夏令时期间,它位于新南威尔士州的-1
偏移处。
(更新:最近,澳大利亚采用了A
前缀,因此使用AEST
作为其东部各州TZ的首字母缩写,但EST
和WST
仍然通用)。
困惑多了?
如果您只需要存储UTC偏移,则interval
是合适的。如果要存储时区,请将其存储为text
。目前验证和转换为时区偏移是一件很痛苦的事情,但至少它能处理DST。
在理想的情况下,您可以拥有一组已知时区的外键。你可以用视图和域做一些类似的事情。
David E.Wheleer的这篇维基技巧创建了一个域,该域作为时区进行了有效性测试:
CREATE OR REPLACE FUNCTION is_timezone( tz TEXT ) RETURNS BOOLEAN as $$
BEGIN
PERFORM now() AT TIME ZONE tz;
RETURN TRUE;
EXCEPTION WHEN invalid_parameter_value THEN
RETURN FALSE;
END;
$$ language plpgsql STABLE;
CREATE DOMAIN timezone AS CITEXT
CHECK ( is_timezone( value ) );
有一个已知时区的列表是很有用的,在这种情况下,您可以省去域,只在一个包含已知时区名称的表中强制执行约束(从视图pg_timezone_names
中获得),从而避免在其他地方公开域:
CREATE TABLE tzone
(
tzone_name text PRIMARY KEY (tzone_name) CHECK (is_timezone(tzone_name))
);
INSERT INTO tzone (tzone_name)
SELECT name FROM pg_timezone_names;
然后您可以通过外键强制执行正确性:
CREATE TABLE myTable (
...
tzone TEXT REFERENCES tzone(tzone_name)
);
在postgres中,您已经可以将任何TIMESTAMP
或TIMESTAMPTZ
强制转换到命名时区或从命名时区强制转换,因此您不需要从表中查找值。您可以在检查约束中直接使用此表达式,因此也不需要为此创建函数:
CREATE TABLE locations (
location_id SERIAL PRIMARY KEY,
name TEXT,
timezone TEXT NOT NULL CHECK (now() AT TIME ZONE timezone IS NOT NULL)
);
如果你试图插入一个不包含有效时区的值,你会得到一个用户友好的错误:
INSERT INTO locations (name, timezone) VALUES ('foo', 'Adelaide/Australia');
ERROR: time zone "Adelaide/Australia" not recognized
根据您的要求,您可能需要以正常约束违反所提供的格式出现错误,但在许多情况下,这就足够了。
如果您使用的web框架为您提供了一个可以在下拉框中显示的时区列表,那么这种验证应该足够了,然后您的检查约束只是一个备份。
"+hh:mm"one_answers"-hh:mm"不是时区,它们是UTC偏移量。保存这些数据的一个好格式是将其保存为偏移量以分钟为单位的带符号整数。你也可以使用interval
之类的东西,但只有当你想直接在PostgreSQL中进行日期计算时,比如在查询等中,这才会对你有所帮助。通常,尽管你用另一种语言进行这些计算,但这取决于该语言是否很好地支持interval
类型,并且是否具有良好的日期/时间库。但是,将一个整数转换为某种类似interval
的类型,就像Python的timedelta
一样,应该是微不足道的,所以我个人只将其存储为一个整数。
时区有名称,尽管时区没有标准化的名称,但在"tz"或"zoneinfo"数据库中有一个事实上的标准,即"欧洲/巴黎"、"美洲/纽约"或"美国/太平洋"等名称。这些应该存储为字符串。
Windows使用完全不同的名称,例如"浪漫时间"(不要问)。你可以将它们和字符串一起存储,但我会避免,这些名称在Windows之外不会使用,而且这些名称毫无意义。此外,windows的翻译版本倾向于使用这些时区的翻译名称,这使情况变得更糟。
像"PDT"one_answers"EST"这样的缩写不能用作时区名称,因为它们不是唯一的。有四个(我想是五个吗?)不同的时区都被称为"CST",所以这是不可用的。
简而言之:对于时区,将名称存储为字符串。对于UTC偏移量,以分钟为单位将偏移量存储为带符号整数
可能间隔
postgres=#选择时间间隔01:30';间隔----------01:30:00(1排)postgres=#选择间隔'-01:30';间隔------------01:30:00(1行)