将UTC中的当前时间用作PostgreSQL中的默认值


172

我有一个TIMESTAMP WITHOUT TIME ZONE类型的列,希望将该默认值设置为UTC的当前时间。使用UTC来获取当前时间很容易:

postgres=# select now() at time zone 'utc';
          timezone          
----------------------------
 2013-05-17 12:52:51.337466
(1 row)

与使用当前时间戳记的列相同:

postgres=# create temporary table test(id int, ts timestamp without time zone default current_timestamp);
CREATE TABLE
postgres=# insert into test values (1) returning ts;
             ts             
----------------------------
 2013-05-17 14:54:33.072725
(1 row)

但这使用当地时间。尝试将其强制为UTC会导致语法错误:

postgres=# create temporary table test(id int, ts timestamp without time zone default now() at time zone 'utc');
ERROR:  syntax error at or near "at"
LINE 1: ...int, ts timestamp without time zone default now() at time zo...

Answers:


297

甚至不需要功能。只需在默认表达式周围加上括号即可:

create temporary table test(
    id int, 
    ts timestamp without time zone default (now() at time zone 'utc')
);

2
我可以看到像now_utc()这样的函数在编写查询时确实发光
misaxi 2015年

甚至当时间回到一小时时,它也可以工作-now()返回一个时间戳,该时间戳知道与UTC的偏移量。
克莱·伦哈特

1
FWIW,在PostgreSQL 11.5中运行此查询:ALTER TABLE testcase_result ADD COLUMN date_created TIMESTAMP WITHOUT TIME ZONE DEFAULT (NOW() AT TIME ZONE "UTC") NOT NULL;失败:ERROR: column "UTC" does not exist确保'utc'全部为小写。
–'code_dredd

2
更正:'utc'字符串也必须单引号,而不是双引号。
–'code_dredd

56

另一个解决方案:

timezone('utc', now())

26

将其包装在一个函数中:

create function now_utc() returns timestamp as $$
  select now() at time zone 'utc';
$$ language sql;

create temporary table test(
  id int,
  ts timestamp without time zone default now_utc()
);

16

关于什么

now()::timestamp

如果您的其他时间戳记没有时区,则此强制转换将产生当前时间的匹配类型“无时区的时间戳记”。

不过,我想阅读其他人对该选项的看法。我仍然不相信我对这种“有/没有”时区的理解。

编辑:在此处添加Michael Ekoka的评论,因为它阐明了重要的一点:

警告。问题是关于在UTC中为恰好不存储时区的timestamp列生成默认时间戳(也许是因为如果您知道所有时间戳都共享时区,则无需存储时区)。您的解决方案要做的是生成一个本地时间戳(对于大多数人而言,不一定将其设置为UTC)并将其存储为纯朴的时间戳(未指定其时区的时间戳)。


这是一个有趣的技巧,但是除非您意识到此行为,否则它可能导致混乱。可接受的答案在所需的操作和结果上非常清晰。同样的,在功能,但我从功能敬而远之在DB的....
弗兰克V

在我的选择中,它将生成本地日期时间到数据库中
VelikiiNehochuha '18 -10-9

警告。问题是关于在UTC中为恰好不存储时区的timestamp列生成默认时间戳(也许是因为如果您知道所有时间戳都共享时区,则无需存储时区)。您的解决方案要做的是生成一个本地时间戳(对于大多数人而言,不一定将其设置为UTC)并将其存储为纯朴的时间戳(未指定其时区的时间戳)。
Michael Ekoka,

@MichaelEkoka我已将您的评论添加到答案中-如果需要,请继续进行编辑。您正在非常清楚地解释它。谢谢!
Risadinha

警告:带有时区的时间戳字段不存储时区,这与合理的假设相反。请参阅下面的链接,并在页面上搜索UTC。输入时,带有时区的时间戳会将输入的值转换为utc,并在没有时区或偏移信息的情况下存储该值。输出时,将使用客户端的时区(如果有)将存储的utc值转换为本地时间。此类型与查询时的值转换有关。您应该通过从一个时区进行存储并从另一个时区进行选择来进行测试。postgresql.org/docs/11/datatype-datetime.html
汤姆

7

这些是2个等效的解决方案:

(下面的代码,你应该取代'UTC'now()用于时间戳

  1. timestamp AT TIME ZONE zone -符合SQL标准
  2. timezone(zone, timestamp) -更具可读性

函数timezone(zone,timestamp)等效于符合SQL的构造时间戳AT TIME ZONE区域。


说明:

  • 区域可以指定为文本字符串(例如'UTC')或间隔(例如INTERVAL '-08:00')-这是所有可用时区的列表
  • 时间戳记可以是时间戳记类型的任何值
  • now()返回一个timestamp类型的值(正是我们需要的值),并附加了数据库的默认时区(例如2018-11-11T12:07:22.3+05:00)。
  • timezone('UTC', now())将当前时间(带有时区的timestamp类型的时间)转换为中的无时区等效项UTC
    例如,SELECT timestamp with time zone '2020-03-16 15:00:00-05' AT TIME ZONE 'UTC'将返回2020-03-16T20:00:00Z

文件:timezone()


1
谢谢总结这些事情。我使用的是小写版本at timezone 'utc',但不适用于我的PostgreSQL设置。使用大写字母解决了问题
Geradlus_RU,

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.