sle*_*vin 2 postgresql timezone timestamp timezone-offset timestamp-with-timezone
我试图了解Postgre中的时间戳和时区。我想我明白了,直到我写这篇文章为止。
专注于“在时区之间转换”部分。它有两个例子。
(将默认时区配置考虑为UTC。)
例子1
db=# SELECT timezone('US/Pacific', '2016-01-01 00:00'); outputs 2015-12-31 16:00:00
Run Code Online (Sandbox Code Playgroud)
根据本文和我的理解,由于该函数的'2016-01-01 00:00'一部分timezone只是一个字符串,因此将其静默转换为默认的UTC。因此,'2016-01-01 00:00' UTC然后将其转换US/Pacific为timezone函数所要求的,即2015-12-31 16:00:00。
例子2
db=# SELECT timezone('US/Pacific', '2016-01-01 00:00'::timestamp); outputs 2016-01-01 08:00:00+00
Run Code Online (Sandbox Code Playgroud)
不好意思,我不明白为什么,那里的解释也无济于事。好的,函数的'2016-01-01 00:00'::timestamp一部分timezone不再是字符串,而是实际的时间戳。在什么时区?如果是UTC,则输出必须与示例1相同。因此,它将自动转换为US/Pacific?。那么输出是UTC吗?但为什么?我要求的 不是US/Pacific我timezone的UTC。
请说明timezone何时获取时间戳并被要求转换时间戳时的行为。谢谢。
让我解释两个例子:
在这两种情况下,我们都假设一个时区UTC(即SET timezone TO UTC)。
db=# SELECT timezone('US/Pacific', '2016-01-01 00:00');
timezone
---------------------
2015-12-31 16:00:00
(1 row)
Run Code Online (Sandbox Code Playgroud)
这相当于SELECT timezone('US/Pacific', '2016-01-01 00:00'::timestamptz),即Postgres将字符串隐式转换为timestamptz。
我们知道timezone函数在timestamp和之间来回转换timestamptz:
由于我们将其timestamptz作为输入,因此将输出timestamp。换句话说,它将绝对时间点转换2016-01-01 00:00Z为中的墙上时间US/Pacific,即洛杉矶的时钟在该绝对时间点上显示的时间。
在示例2中,我们做相反的事情,即取a timestamp并将其转换为a timestamptz。换句话说,我们在问:洛杉矶时钟显示的绝对时间是2016-01-01 00:00几点?
您提到:
好的,
'2016-01-01 00:00'::timestamp时区函数的一部分不再是字符串,而是实际的时间戳。在什么时区?
'2016-01-01 00:00'::timestamp是timestamp,即挂墙时间。它没有时区的概念。
我想你可能没有完全理解之间的差异timestamp和timestamptz在这里是关键。可以将它们视为壁钟时间,即挂在墙上的时钟在世界某个地方显示的时间,以及绝对时间,即我们宇宙中的绝对时间。
您自己回答的例子并不十分准确。
SELECT ts FROM (VALUES
(timestamptz '2012-03-05 17:00:00+0') -- outputs 2012-03-05 17:00:00+00 --1
,(timestamptz '2012-03-05 18:00:00+1') -- outputs 2012-03-05 17:00:00+00 --2
,(timestamp '2012-03-05 18:00:00+1') -- outputs 2012-03-05 18:00:00+00 --3
,(timestamp '2012-03-05 11:00:00' AT TIME ZONE '+6') -- outputs 2012-03-05 17:00:00+00 --4
,(timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC') -- outputs 2012-03-05 17:00:00+00 --5
,(timestamp '2012-03-05 17:00:00'::timestamp) -- outputs 2012-03-05 17:00:00+00 --6
,(timestamp '2012-03-05 17:00:00'::timestamptz) -- outputs 2012-03-05 17:00:00+00 --7
) t(ts);
Run Code Online (Sandbox Code Playgroud)
您的示例的问题在于,您正在用单个列构造一个数据集。由于列只能具有一种类型,因此timestamptz即使计算出某些值timestamp(例如,值3),每一行(或在这种情况下为单个值)也将转换为同一类型。因此,您在此处有一个附加的隐式转换。
让我们将示例拆分为单独的查询,看看发生了什么:
例子1
db=# SELECT timestamptz '2012-03-05 17:00:00+0';
timestamptz
------------------------
2012-03-05 17:00:00+00
Run Code Online (Sandbox Code Playgroud)
如您可能已经知道的,timestamptz '2012-03-05 17:00:00+0'并且'2012-03-05 17:00:00+0'::timestamptz是等效的(我更喜欢后者)。因此,仅使用与文章中相同的语法,我将重写:
db=# SELECT '2012-03-05 17:00:00+0'::timestamptz;
timestamptz
------------------------
2012-03-05 17:00:00+00
Run Code Online (Sandbox Code Playgroud)
现在,这是怎么回事?好吧,少于您最初的解释。该字符串被简单地解析为timestamptz。打印结果时,它将使用当前设置的timezone配置将其转换回基础数据结构(即)的可读格式2012-03-05 17:00:00+00。
让我们更改timezone配置,看看会发生什么:
db=# SET timezone TO 'Europe/Berlin';
SET
db=# SELECT '2012-03-05 17:00:00+0'::timestamptz;
timestamptz
------------------------
2012-03-05 18:00:00+01
Run Code Online (Sandbox Code Playgroud)
那唯一改变的是如何将timestamptz显示在屏幕上得到,即使用欧洲/柏林时区。
例子2
db=# SELECT timestamptz '2012-03-05 18:00:00+1';
timestamptz
------------------------
2012-03-05 17:00:00+00
(1 row)
Run Code Online (Sandbox Code Playgroud)
同样,仅解析日期。
例子3
db=# SELECT timestamp '2012-03-05 18:00:00+1';
timestamp
---------------------
2012-03-05 18:00:00
(1 row)
Run Code Online (Sandbox Code Playgroud)
这与相同'2012-03-05 18:00:00+1'::timestamp。此处发生的是,因为您要求输入,所以时区偏移量被忽略了timestamp。
例子4
db=# SELECT timestamp '2012-03-05 11:00:00' AT TIME ZONE '+6';
timezone
------------------------
2012-03-05 17:00:00+00
(1 row)
Run Code Online (Sandbox Code Playgroud)
让我们更简单地重写:
db=# SELECT timezone('+6', '2012-03-05 11:00:00'::timestamp);
timezone
------------------------
2012-03-05 17:00:00+00
(1 row)
Run Code Online (Sandbox Code Playgroud)
这是在问:显示时区墙上的时钟偏移+6小时的绝对时间是2012-03-05 11:00:00什么?
例子5
db=# SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC';
timezone
------------------------
2012-03-05 17:00:00+00
(1 row)
Run Code Online (Sandbox Code Playgroud)
让我们重写:
db=# SELECT timezone('UTC', '2012-03-05 17:00:00'::timestamp);
timezone
------------------------
2012-03-05 17:00:00+00
(1 row)
Run Code Online (Sandbox Code Playgroud)
这是在问:UTC时区的墙上的时钟显示的绝对时间是2012-03-05 17:00:00几点?
例子6
db=# SELECT timestamp '2012-03-05 17:00:00'::timestamp;
timestamp
---------------------
2012-03-05 17:00:00
(1 row)
Run Code Online (Sandbox Code Playgroud)
在这里,您将两次投射到timestamp,这没有什么区别。让我们简化一下:
db=# SELECT '2012-03-05 17:00:00'::timestamp;
timestamp
---------------------
2012-03-05 17:00:00
(1 row)
Run Code Online (Sandbox Code Playgroud)
我认为这很明显。
例子7
db=# SELECT timestamp '2012-03-05 17:00:00'::timestamptz;
timestamptz
------------------------
2012-03-05 17:00:00+00
(1 row)
Run Code Online (Sandbox Code Playgroud)
让我们重写:
db=# SELECT ('2012-03-05 17:00:00'::timestamp)::timestamptz;
timestamptz
------------------------
2012-03-05 17:00:00+00
(1 row)
Run Code Online (Sandbox Code Playgroud)
首先,您将字符串解析为a timestamp,然后timestamptz使用当前设置将其转换为a timezone。如果更改timezone,则会得到其他信息,因为Postgres在将timestamp(或缺少时区信息的字符串)转换为时会采用该时区timestamptz:
db=# SET timezone TO 'Europe/Berlin';
SET
db=# SELECT ('2012-03-05 17:00:00'::timestamp)::timestamptz;
timestamptz
------------------------
2012-03-05 17:00:00+01
(1 row)
Run Code Online (Sandbox Code Playgroud)
因此,以UTC表示的绝对时间2012-03-05 16:00:00+00与原始示例不同。
我希望这可以使事情澄清。同样,理解之间的差别timestamp,并timestamptz为关键。考虑墙壁时间与绝对时间。
| 归档时间: |
|
| 查看次数: |
4275 次 |
| 最近记录: |