将 postgres 日期表示转换为 ISO 8601 字符串

Turn postgres date representation into ISO 8601 string

我正在尝试将 Postgres 日期表示形式格式化为 ISO 8601 字符串。我假设有一个 Postgres 函数可以做到这一点,但我发现文档中的示例很少。

我的查询是

SELECT
  now()::timestamp

哪个returns

[{{2016, 8, 9}, {3, 56, 55, 754181}}]

我正在尝试将日期转换为看起来更像的格式 2016-8-9T03:56:55+00:00

我需要对我的查询进行哪些更改才能实现这一目标?感谢您的帮助。

我想我找到了一种格式化的方法,但它并不理想,因为我正在自己编写格式化。

这是一个可能的解决方案:

SELECT to_char (now()::timestamp at time zone 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')

只有功能对我有用,因为你需要设置时区。

要使用带默认值的时区:

create table somedata (
  release_date timestamptz DEFAULT NOW()
)

创建 function:

CREATE OR REPLACE FUNCTION date_display_tz(param_dt timestamp with time zone)
 RETURNS text AS
$$
DECLARE var_result varchar;
BEGIN
PERFORM set_config('timezone', 'UTC', true);
var_result := to_char(param_dt , 'YYYY-MM-DD"T"HH24:MI:SS:MS"Z"');
RETURN var_result;
END;
$$ language plpgsql VOLATILE;

并输出:

# SELECT
#   localtimestamp, current_timestamp,
#   to_char(localtimestamp, 'YYYY-MM-DD"T"HH24:MI:SS:MS"Z"'),
#   to_char(current_timestamp, 'YYYY-MM-DD"T"HH24:MI:SS:MS"Z"'),
#   date_display_tz(localtimestamp), date_display_tz(current_timestamp);
         timestamp          |              now              |         to_char          |         to_char          |     date_display_tz      |     date_display_tz
----------------------------+-------------------------------+--------------------------+--------------------------+--------------------------+--------------------------
 2017-04-27 23:48:03.802764 | 2017-04-27 21:48:03.802764+00 | 2017-04-27T23:48:03:802Z | 2017-04-27T23:48:03:802Z | 2017-04-27T21:48:03:802Z | 2017-04-27T21:48:03:802Z
(1 row)

再看看this

If you want the server to return time zone information respective of another time zone, I believe you'll need to use SET TIME ZONE. Otherwise, the server automatically (converts the timestamp) and returns the time zone of the server.

test=# select (current_timestamp at time zone 'UTC') at time zone 'UTC';
            timezone
-------------------------------
  2005-04-22 16:26:57.209082+09
(1 row)

test=# set time zone 'UTC';
SET
test=# select (current_timestamp at time zone 'UTC') at time zone 'UTC';
            timezone
-------------------------------
  2005-04-22 07:27:55.841596+00
(1 row)

test=# select (current_timestamp at time zone 'UTC');
           timezone
----------------------------
  2005-04-22 07:28:48.888154
(1 row)

test=# select (current_timestamp at time zone 'UTC')::timestamptz;
            timezone
-------------------------------
  2005-04-22 07:38:19.979511+00
(1 row)

也许对于某些人来说,了解自 Postgres 9.4 to_json 函数(以及 row_to_json)也将时间戳转换为适当的 ISO 8601 格式但另外它包装一个值可能会有所帮助在可能不受欢迎的引号中:

SELECT now();
  2017-05-10 15:57:23.736054+03

SELECT to_json(now());
  "2017-05-10T15:57:23.769561+03:00"

-- in case you want to trim the quotes
SELECT trim(both '"' from to_json(now())::text);
  2017-05-10T15:57:23.806563+03:00

timezone 会话变量设置为您希望输出所在的任何时区,然后使用 to_char(now(), 'YYYY-MM-DD"T"HH24:MI:SSOF')

如果您使用 at time zone '...' 请注意,这将去除所有时区信息,并假设用户已经知道时区。

如果您使用 at time zone 'UTC',则输出应始终为 UTC 时间,并带有正确的时区信息(无偏移)。

set timezone='UTC';


select to_char(now(), 'YYYY-MM-DD"T"HH24:MI:SSOF');

2017-11-17T02:02:26+00  /* UTC time */


select to_char(now() at time zone 'Australia/Sydney', 'YYYY-MM-DD"T"HH24:MI:SSOF');

2017-11-17T13:02:26+00  /* Local Sydney time, but note timezone is incorrect. */


set timezone='Australia/Sydney';


select to_char(now(), 'YYYY-MM-DD"T"HH24:MI:SSOF');

2017-11-17T13:02:26+11  /* Local Sydney time with correct time zone! */


select to_char(now() at time zone 'Australia/Sydney', 'YYYY-MM-DD"T"HH24:MI:SSOF');

2017-11-17T13:02:26+00  /* Still local Sydney time, but time zone info has been removed. */


select to_char(now() at time zone 'UTC', 'YYYY-MM-DD"T"HH24:MI:SSOF');

2017-11-17T02:02:26+00  /* Correct UTC time with correct offset. */

This blog post解释的很详细

这是“将 PostgreSQL 日期表示形式转换为 ISO 8601 字符串”的简洁方法:

SELECT to_json(now())#>>'{}'

它结合使用 #>> 运算符和 to_json() 函数,两者都可以在此页面上找到: https://www.postgresql.org/docs/current/functions-json.html

运算符“获取[s] JSON 指定路径的对象作为文本”。但是,当您将空数组文字 '{}' 指定为路径时,它会指定根对象。

将此方法与类似方法进行比较:

SELECT
to_char(now(), 'YYYY-MM-DD"T"HH24:MI:SSOF') AS most_lengthy, -- See note: *
trim(both '"' from to_json(now())::text) AS a_bit_lengthy,
to_json(now())::text AS unwanted_quotes,
to_json(now())#>>'{}' AS just_right

它更短但产生相同的结果。

用户@atoth 指出亚秒分量使用 to_json() 删除了尾随零,因此 2022-03-31 17:39:23.500 被转换为 2022-03-31T17:39:23.5Z。由于一些日期收件人需要非常特定的格式,我测试了以下内容:

SELECT
to_char('2022-03-31 17:39:23.5'::timestamp, 'YYYY-MM-DD"T"HH24:MI:SS.MSOF'),
to_char('2022-03-31 17:39:23.500'::timestamp, 'YYYY-MM-DD"T"HH24:MI:SS.MSOF'),
to_char('2022-03-31 17:39:23.5123456789'::timestamp, 'YYYY-MM-DD"T"HH24:MI:SS.MSOF'),
to_char('2022-03-31 17:39:23.5123456789'::timestamp, 'YYYY-MM-DD"T"HH24:MI:SS.USOF')

这是 Postgres 10 的输出:

"2022-03-31T17:39:23.500+00", "2022-03-31T17:39:23.500+00", "2022-03-31T17:39:23.512+00", "2022-03-31T17:39:23.512346+00"

所以看起来 MS 您可以指定 3 位小数,不多也不少,而 US 您将得到 6 位小数,不多也不少。除了这两个精度选项之外,您还必须进行一些时髦的字符串操作。

玩得开心!

* 此外,JavaScript 不会通过 Date() 构造函数解析第一个方法的输出,因为它期望 simplification of the ISO 8601 只接受 中的时区( +/-)HH:mmZ 格式,但 OF returns (+/-)HH 没有分钟的格式,除非输入时区是小时的一小部分,例如在会话开始时使用 SET timezone=-4.5;。或者,您可以手动将时区作为字符串附加到冗长的版本中,并排除 OF

Simple/trivial:

SELECT REPLACE(NOW()::TEXT, ' ', 'T');

或者如果爱好者需要使用

REGEXP_REPLACE()