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

agxfikkp  于 2023-01-02  发布在  PostgreSQL
关注(0)|答案(6)|浏览(221)

我尝试将Postgres日期表示格式转换为ISO8601字符串,我假设有一个Postgres函数可以做到这一点,但我发现文档中缺少示例。
我的问题是

SELECT
  now()::timestamp

其返回

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

我正在尝试将日期转换为看起来更像2016-8-9T03:56:55+00:00的格式。
我需要对我的查询做什么修改才能做到这一点?谢谢你的帮助。

js4nwp54

js4nwp541#

我想我找到了一种方法来做格式,但它不是理想的,因为我自己写的格式。
下面是一个可能的解决方案:

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

s2j5cfk02#

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

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

它结合使用#>>运算符和to_json()函数,两者都可以在此页面上找到:https://www.postgresql.org/docs/current/functions-json.html
运算符"获取指定路径的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

它更短,但产生相同的结果。
User@atoth指出,使用to_json()删除了subsecond部分的尾随零,因此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()构造函数解析第一个方法的输出,因为它期望简化ISO 8601,ISO 8601只接受 *(+/-)HH:mm * 或 * Z * 格式的时区,但是OF返回不带分钟的 *(+/-)HH * 格式,除非输入时区是小时的一部分,例如在会话开始时使用SET timezone=-4.5;。或者,您可以手动将时区作为字符串附加到冗长的版本中,并排除OF
wlsrxk51

wlsrxk513#

也许对某些人来说,知道以下内容会很有帮助: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
f8rj6qna

f8rj6qna4#

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给出了相当详细的解释。

rta7y2nd

rta7y2nd5#

唯一的功能为我工作,因为你需要设置时区。
若要使时区具有默认值timezone:

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
如果你想让服务器返回另一个时区的时区信息,我相信你需要使用SET TIME ZONE,否则,服务器会自动(转换时间戳)返回服务器的时区。

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)
ve7v8dk2

ve7v8dk26#

简单/琐碎:

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

或者如果爱好者需要使用

REGEXP_REPLACE()

相关问题