jl6*_*jl6 19 postgresql timezone datetime sqldatatypes
我想简单地使用"+ hh:mm"(或"-hh:mm")格式的字符串.这既充实又充足?
注意:我不需要存储日期或时间,只需存储时区.
Cra*_*ger 27
不幸的是PostgreSQL没有提供时区数据类型,所以你应该使用它text.
interval好像乍一看合理的选择,它是适用于某些用途.但是,它没有考虑夏令时,也没有考虑同一UTC偏移中的不同区域具有不同的DST规则这一事实.
从UTC偏移回到时区没有1:1的映射.
例如,Australia/Sydney(新南威尔士州)的时区是夏令时期间的UTC+10(EST)或UTC+11(EDT).是的,这EST与美国使用的首字母缩略词相同; 时区首字母缩略词在tzdata数据库中是非唯一的,这就是Pg具有timezone_abbreviations设置的原因.更糟糕的是,布里斯班(昆士兰州)几乎处于相同的长度并且处于UTC+10 EST......但没有夏令时,所以有时它会在-1新南威尔士州的DST期间抵消新南威尔士州.
(更新:最近澳大利亚采用的A前缀,所以它使用AEST它的东部各州TZ缩写,但EST并WST留在共同使用).
困惑多少?
如果你需要存储的只是一个UTC偏移,那么a interval是合适的.如果要存储时区,请将其存储为text.现在验证并转换为时区偏移是一种痛苦,但至少它应对DST.
Len*_*bro 14
"+ hh:mm"和"-hh:mm"不是时区,它们是UTC偏移量.保存它们的一种好格式是带符号的整数,偏移量以分钟为单位.您也可以使用之类的东西interval,但如果你想直接做日期计算PostgreSQL中,像查询等.通常虽然你用另一种语言这些计算,这将不仅帮助你,然后它取决于语言,如果它支持该interval型好,具有良好的日期/时间库与否.但是将一个整数转换成某种类似的interval类型,比如Pythons timedelta应该是微不足道的,所以我个人只是将它存储为整数.
时区有名字,虽然没有标准化的名字时区存在的"TZ"或"区信息"数据库中的一个事实上的标准,那就是像"欧洲/巴黎"的名字,"美洲/纽约"或"美国/太平洋".那些应该存储为字符串.
Windows使用完全不同的名称,例如"浪漫时间"(不要问).你可以存储它们以及字符串,但我会避免它,这些名称不在Windows之外使用,名称没有意义.此外,Windows的翻译版本倾向于使用这些时区的翻译名称,使其更糟糕.
像"PDT"和"EST"这样的缩写词不能用作时区名称,因为它们不是唯一的.有四个(我认为,或者它是五个?)不同的时区都被称为"CST",所以这是不可用的.
简而言之:对于时区,将名称存储为字符串.对于UTC偏移,将偏移量以分钟为单位存储为有符号整数.
bel*_*daz 13
在理想的世界中,您可以拥有一组已知时区的外键.您可以使用视图和域执行与此相近的操作.
这个由David E. Wheleer创建的wiki提示创建了一个域,该域以其作为时区的有效性进行测试:
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 ) );
Run Code Online (Sandbox Code Playgroud)
拥有已知时区列表很有用,在这种情况下,您可以省去域,只需在包含已知时区名称(从视图中获取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;
Run Code Online (Sandbox Code Playgroud)
然后,您可以通过外键强制执行正确性:
CREATE TABLE myTable (
...
tzone TEXT REFERENCES tzone(tzone_name)
);
Run Code Online (Sandbox Code Playgroud)
Mat*_*kel 11
在 postgres 中,您已经可以将 anyTIMESTAMP或TIMESTAMPTZto 或 from a named timezone 进行转换,因此您无需从表中查找值。您可以直接在检查约束中使用此表达式,因此您也不需要为此创建函数:
CREATE TABLE locations (
location_id SERIAL PRIMARY KEY,
name TEXT,
timezone TEXT NOT NULL CHECK (now() AT TIME ZONE timezone IS NOT NULL)
);
Run Code Online (Sandbox Code Playgroud)
如果您尝试插入一个不包含有效时区的值,您将收到一个实际上对用户友好的错误:
INSERT INTO locations (name, timezone) VALUES ('foo', 'Adelaide/Australia');
ERROR: time zone "Adelaide/Australia" not recognized
Run Code Online (Sandbox Code Playgroud)
根据您的要求,您可能需要错误的格式符合正常的约束违规,但在许多情况下,这已经足够了。
如果您使用的 Web 框架为您提供下拉框中可以包含的时区列表,那么此验证应该就足够了,然后您的检查约束只是一个备份。
| 归档时间: |
|
| 查看次数: |
11827 次 |
| 最近记录: |