表 9.33 显示了可用于日期/时间值处理的可用函数,详细信息在以下小节中给出。 表 9.32 说明了基本算术运算符(+
,*
等)的行为。有关格式化函数,请参阅 第 9.8 节。您应该熟悉来自 第 8.5 节 的日期/时间数据类型的背景信息。
此外,表 9.1 中显示的常用比较运算符可用于日期/时间类型。日期和时间戳(带或不带时区)都是可比较的,而时间(带或不带时区)和间隔只能与相同数据类型的其他值进行比较。当将不带时区的时间戳与带时区的时间戳进行比较时,假定前一个值以 TimeZone 配置参数指定的时区给出,并在与后一个值进行比较时旋转为 UTC(后一个值在内部已为 UTC)。类似地,当将日期值与时间戳进行比较时,假定日期值代表 TimeZone
时区的午夜。
以下所有接受 time
或 timestamp
输入的函数和运算符实际上都有两个变体:一个接受 time with time zone
或 timestamp with time zone
,另一个接受 time without time zone
或 timestamp without time zone
。为简洁起见,这些变体没有单独显示。此外,+
和 *
运算符以可交换对的形式出现(例如,date
+
integer
和 integer
+
date
);我们只显示其中之一。
表 9.32. 日期/时间运算符
运算符 描述 示例 |
---|
将一定数量的天数加到日期
|
将一个间隔加到日期
|
将一天中的时间加到日期
|
加间隔
|
将一个间隔加到时间戳
|
将一个间隔加到时间
|
取一个间隔的负值
|
减去日期,产生经过的天数
|
从日期中减去一定数量的天数
|
从日期中减去一个间隔
|
减去时间
|
从时间中减去一个间隔
|
从时间戳中减去一个间隔
|
减去间隔
|
减去时间戳(将 24 小时间隔转换为天,类似于
|
将一个间隔乘以一个标量
|
将一个间隔除以一个标量
|
表 9.33. 日期/时间函数
函数 描述 示例 |
---|
减去参数,产生一个“符号”结果,它使用年份和月份,而不是仅仅使用天数
|
从
|
当前日期和时间(在语句执行期间更改);见 第 9.9.5 节
|
当前日期;见 第 9.9.5 节
|
当前时间;参见 第 9.9.5 节
|
当前时间,精度有限;参见 第 9.9.5 节
|
当前日期和时间(当前事务开始时间);参见 第 9.9.5 节
|
当前日期和时间(当前事务开始时间),精度有限;参见 第 9.9.5 节
|
将一个
|
将输入分箱到以指定原点对齐的指定间隔;参见 第 9.9.3 节
|
获取 timestamp 子字段(等效于
|
获取 interval 子字段(等效于
|
从
|
截断到指定精度;参见 第 9.9.2 节
|
在指定时区中截断到指定精度;参见 第 9.9.2 节
|
截断到指定精度;参见 第 9.9.2 节
|
获取 timestamp 子字段;参见 第 9.9.1 节
|
获取 interval 子字段;参见 第 9.9.1 节
|
测试日期是否有限(非 +/-infinity)
|
测试 timestamp 是否有限(非 +/-infinity)
|
测试 interval 是否有限(非 +/-infinity)
|
调整间隔,将 30 天时间段转换为月
|
调整间隔,将 24 小时时间段转换为天
|
使用
|
当前时间;参见 第 9.9.5 节
|
当前时间,精度有限;参见 第 9.9.5 节
|
当前日期和时间(当前事务开始时间);参见 第 9.9.5 节
|
当前日期和时间(当前事务开始时间),精度有限;参见 第 9.9.5 节
|
从年份、月份和日期字段创建日期(负年份表示公元前)
|
从年份、月份、周、天、小时、分钟和秒字段创建间隔,这些字段都可以默认为零
|
从小时、分钟和秒字段创建时间
|
从年份、月份、日期、小时、分钟和秒字段创建 timestamp(负年份表示公元前)
|
从年份、月份、日期、小时、分钟和秒字段创建带时区的 timestamp(负年份表示公元前)。如果未指定
|
当前日期和时间(当前事务开始时间);参见 第 9.9.5 节
|
当前日期和时间(当前语句开始时间);参见 第 9.9.5 节
|
当前日期和时间(类似于
|
当前日期和时间(当前事务开始时间);参见 第 9.9.5 节
|
将 Unix 纪元(自 1970-01-01 00:00:00+00 起的秒数)转换为带时区的时间戳
|
(start1
,end1
) OVERLAPS (start2
,end2
) (start1
,length1
) OVERLAPS (start2
,length2
)
当两个时间段(由其端点定义)重叠时,此表达式返回真值,当它们不重叠时,返回假值。端点可以指定为日期、时间或时间戳对;或作为日期、时间或时间戳,后跟一个时间间隔。当提供一对值时,可以先写开始或结束;OVERLAPS
自动将对中的较早值视为开始。每个时间段都被认为代表半开区间 start
<=
time
<
end
,除非 start
和 end
相等,在这种情况下,它表示该单个时间点。这意味着例如,只有公共端点的两个时间段不会重叠。
SELECT (DATE '2001-02-16', DATE '2001-12-21') OVERLAPS (DATE '2001-10-30', DATE '2002-10-30'); Result:true
SELECT (DATE '2001-02-16', INTERVAL '100 days') OVERLAPS (DATE '2001-10-30', DATE '2002-10-30'); Result:false
SELECT (DATE '2001-10-29', DATE '2001-10-30') OVERLAPS (DATE '2001-10-30', DATE '2001-10-31'); Result:false
SELECT (DATE '2001-10-30', DATE '2001-10-30') OVERLAPS (DATE '2001-10-30', DATE '2001-10-31'); Result:true
将 interval
值添加到(或从 timestamp
或 timestamp with time zone
值中减去 interval
值)时,interval
值的月、日和微秒字段将依次处理。首先,非零月份字段将时间戳的日期向前或向后移动指定的月份数,保持月份中的日期相同,除非它会超过新月份的结束,在这种情况下,将使用该月份的最后一天。(例如,3 月 31 日加 1 个月变为 4 月 30 日,但 3 月 31 日加 2 个月变为 5 月 31 日。)然后,日期字段将时间戳的日期向前或向后移动指定的天数。在这两个步骤中,本地时间保持不变。最后,如果存在非零微秒字段,则直接添加或减去该字段。当对带有时区的时间戳值进行算术运算时,该值位于识别夏令时的时区中,这意味着添加或减去(例如)interval '1 day'
不一定与添加或减去 interval '24 hours'
产生相同的结果。例如,将会话时区设置为 America/Denver
SELECT timestamp with time zone '2005-04-02 12:00:00-07' + interval '1 day'; Result:2005-04-03 12:00:00-06
SELECT timestamp with time zone '2005-04-02 12:00:00-07' + interval '24 hours'; Result:2005-04-03 13:00:00-06
这是因为由于时区 America/Denver
中夏令时的变化,在 2005-04-03 02:00:00
时跳过了一个小时。
请注意,age
返回的 months
字段可能会存在歧义,因为不同的月份有不同的天数。PostgreSQL 的方法是在计算部分月份时使用两个日期中较早的日期的月份。例如,age('2004-06-01', '2004-04-30')
使用 4 月来产生 1 mon 1 day
,而使用 5 月会产生 1 mon 2 days
,因为 5 月有 31 天,而 4 月只有 30 天。
日期和时间戳的减法也可能很复杂。执行减法的概念上简单的方法是使用 EXTRACT(EPOCH FROM ...)
将每个值转换为秒数,然后减去结果;这会产生两个值之间的 秒数。这将调整每个月的天数、时区更改和夏令时调整。使用 “-
” 运算符对日期或时间戳值进行减法会返回两个值之间的天数(24 小时)和小时/分钟/秒,并进行相同的调整。age
函数返回年、月、日和小时/分钟/秒,执行字段逐一减法,然后调整负字段值。以下查询说明了这些方法之间的差异。示例结果是使用 timezone = 'US/Eastern'
生成的;所使用的两个日期之间有一个夏令时变化
SELECT EXTRACT(EPOCH FROM timestamptz '2013-07-01 12:00:00') - EXTRACT(EPOCH FROM timestamptz '2013-03-01 12:00:00'); Result:10537200.000000
SELECT (EXTRACT(EPOCH FROM timestamptz '2013-07-01 12:00:00') - EXTRACT(EPOCH FROM timestamptz '2013-03-01 12:00:00')) / 60 / 60 / 24; Result:121.9583333333333333
SELECT timestamptz '2013-07-01 12:00:00' - timestamptz '2013-03-01 12:00:00'; Result:121 days 23:00:00
SELECT age(timestamptz '2013-07-01 12:00:00', timestamptz '2013-03-01 12:00:00'); Result:4 mons
EXTRACT
, date_part
#EXTRACT(field
FROMsource
)
extract
函数从日期/时间值中检索子字段,例如年或小时。 source
必须是类型为 timestamp
、date
、time
或 interval
的值表达式。(时间戳和时间可以有或没有时区。) field
是一个标识符或字符串,用于选择从源值中提取哪个字段。并非所有字段对每种输入数据类型都有效;例如,小于一天的字段不能从 date
中提取,而一天或更长时间的字段不能从 time
中提取。extract
函数返回类型为 numeric
的值。
以下是有效的字段名称
century
世纪;对于 interval
值,年份字段除以 100
SELECT EXTRACT(CENTURY FROM TIMESTAMP '2000-12-16 12:21:13'); Result:20
SELECT EXTRACT(CENTURY FROM TIMESTAMP '2001-02-16 20:38:40'); Result:21
SELECT EXTRACT(CENTURY FROM DATE '0001-01-01 AD'); Result:1
SELECT EXTRACT(CENTURY FROM DATE '0001-12-31 BC'); Result:-1
SELECT EXTRACT(CENTURY FROM INTERVAL '2001 years'); Result:20
day
月份中的日期(1–31);对于 interval
值,天数
SELECT EXTRACT(DAY FROM TIMESTAMP '2001-02-16 20:38:40'); Result:16
SELECT EXTRACT(DAY FROM INTERVAL '40 days 1 minute'); Result:40
decade
年份字段除以 10
SELECT EXTRACT(DECADE FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 200
dow
一周中的日期,从星期日 (0
) 到星期六 (6
)
SELECT EXTRACT(DOW FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 5
请注意,extract
的一周中的日期编号与 to_char(..., 'D')
函数不同。
doy
一年中的日期(1–365/366)
SELECT EXTRACT(DOY FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 47
epoch
对于 timestamp with time zone
值,自 1970-01-01 00:00:00 UTC 起的秒数(对于该日期之前的时间戳为负);对于 date
和 timestamp
值,自 1970-01-01 00:00:00 起的标称秒数,不考虑时区或夏令时规则;对于 interval
值,时间间隔中的总秒数
SELECT EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40.12-08'); Result:982384720.120000
SELECT EXTRACT(EPOCH FROM TIMESTAMP '2001-02-16 20:38:40.12'); Result:982355920.120000
SELECT EXTRACT(EPOCH FROM INTERVAL '5 days 3 hours'); Result:442800.000000
可以使用 to_timestamp
将纪元值转换回 timestamp with time zone
SELECT to_timestamp(982384720.12);
Result: 2001-02-17 04:38:40.12+00
请注意,将 to_timestamp
应用于从 date
或 timestamp
值中提取的纪元可能会产生误导性的结果:结果将有效地假定原始值以 UTC 方式给出,而实际情况可能并非如此。
hour
小时字段(时间戳中为 0–23,时间间隔中不受限制)
SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 20
isodow
一周中的日期,从星期一 (1
) 到星期日 (7
)
SELECT EXTRACT(ISODOW FROM TIMESTAMP '2001-02-18 20:38:40');
Result: 7
这与 dow
相同,只是星期日不同。这与ISO8601 一周中的日期编号匹配。
isoyear
该ISO8601 周编号年,日期属于该年
SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-01'); Result:2005
SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-02'); Result:2006
每个ISO8601 周编号年从包含 1 月 4 日的星期一的星期一开始,因此在 1 月初或 12 月底,ISO年份可能与公历年份不同。有关更多信息,请参见 week
字段。
julian
与日期或时间戳对应的 儒略日。非本地午夜的时间戳会导致分数值。有关更多信息,请参见 第 B.7 节。
SELECT EXTRACT(JULIAN FROM DATE '2006-01-01'); Result:2453737
SELECT EXTRACT(JULIAN FROM TIMESTAMP '2006-01-01 12:00'); Result:2453737.50000000000000000000
microseconds
秒字段(包括小数部分)乘以 1 000 000;请注意,这包括完整的秒
SELECT EXTRACT(MICROSECONDS FROM TIME '17:12:28.5');
Result: 28500000
millennium
千年;对于 interval
值,年份字段除以 1000
SELECT EXTRACT(MILLENNIUM FROM TIMESTAMP '2001-02-16 20:38:40'); Result:3
SELECT EXTRACT(MILLENNIUM FROM INTERVAL '2001 years'); Result:2
1900 年代的年份位于第二个千年。第三个千年从 2001 年 1 月 1 日开始。
milliseconds
秒字段(包括小数部分)乘以 1000。请注意,这包括完整的秒。
SELECT EXTRACT(MILLISECONDS FROM TIME '17:12:28.5');
Result: 28500.000
minute
分钟字段(0–59)
SELECT EXTRACT(MINUTE FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 38
month
一年中月份的编号(1–12);对于 interval
值,月份数模 12(0–11)
SELECT EXTRACT(MONTH FROM TIMESTAMP '2001-02-16 20:38:40'); Result:2
SELECT EXTRACT(MONTH FROM INTERVAL '2 years 3 months'); Result:3
SELECT EXTRACT(MONTH FROM INTERVAL '2 years 13 months'); Result:1
quarter
日期所在的季度(1–4)
SELECT EXTRACT(QUARTER FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 1
second
秒字段(包括任何小数秒)
SELECT EXTRACT(SECOND FROM TIMESTAMP '2001-02-16 20:38:40'); Result:40.000000
SELECT EXTRACT(SECOND FROM TIME '17:12:28.5'); Result:28.500000
timezone
相对于 UTC 的时区偏移量,以秒为单位。正值对应于 UTC 以东的时区,负值对应于 UTC 以西的时区。(从技术上讲,PostgreSQL 不使用 UTC,因为不处理闰秒。)
timezone_hour
时区偏移量的小时部分
timezone_minute
时区偏移量的分钟部分
week
一年中第ISO8601 周编号周。根据定义,ISO 周从星期一开始,一年中的第一周包含该年的 1 月 4 日。换句话说,一年中的第一个星期四位于该年的第 1 周。
在 ISO 周编号系统中,1 月初的日期可能属于前一年的第 52 周或第 53 周,而 12 月底的日期可能属于下一年的第一周。例如,2005-01-01
属于 2004 年的第 53 周,而 2006-01-01
属于 2005 年的第 52 周,而 2012-12-31
属于 2013 年的第一周。建议将 isoyear
字段与 week
字段一起使用以获得一致的结果。
SELECT EXTRACT(WEEK FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 7
year
年份字段。请记住,没有 0 AD
,因此应该谨慎地将 BC
年从 AD
年中减去。
SELECT EXTRACT(YEAR FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 2001
处理 interval
值时,extract
函数会产生与时间间隔输出函数使用的解释匹配的字段值。如果从非规范化时间间隔表示开始,这可能会产生令人惊讶的结果,例如
SELECT INTERVAL '80 minutes'; Result:01:20:00
SELECT EXTRACT(MINUTES FROM INTERVAL '80 minutes'); Result:20
当输入值为 +/-Infinity 时,extract
会为单调递增的字段返回 +/-Infinity(对于 timestamp
输入,epoch
、julian
、year
、isoyear
、decade
、century
和 millennium
;对于 interval
输入,epoch
、hour
、day
、year
、decade
、century
和 millennium
)。对于其他字段,则返回 NULL。9.6 之前的 PostgreSQL 版本在所有无限输入情况下返回零。
extract
函数主要用于计算处理。有关将日期/时间值格式化为显示的格式,请参见 第 9.8 节。
date_part
函数是根据传统的 Ingres 等效于SQL-标准函数 extract
date_part('field
',source
)
请注意,这里的 field
参数需要是字符串值,而不是名称。有效的 date_part
字段名称与 extract
的字段名称相同。出于历史原因,date_part
函数返回值类型为 double precision
。这可能会导致在某些情况下精度丢失。建议使用 extract
代替。
SELECT date_part('day', TIMESTAMP '2001-02-16 20:38:40'); Result:16
SELECT date_part('hour', INTERVAL '4 hours 3 minutes'); Result:4
date_trunc
#date_trunc
函数在概念上类似于数字的 trunc
函数。
date_trunc(field
,source
[,time_zone
])
source
是一个类型为 timestamp
、timestamp with time zone
或 interval
的值表达式。(类型为 date
和 time
的值会自动分别转换为 timestamp
或 interval
。)field
选择将输入值截断到哪个精度。返回值同样是 timestamp
、timestamp with time zone
或 interval
类型,并且它将所有小于所选字段的字段设置为零(或对于天和月,设置为一)。
有效的 field
值是
microseconds |
milliseconds |
second |
minute |
hour |
day |
week |
month |
quarter |
year |
decade |
century |
millennium |
当输入值为 timestamp with time zone
类型时,截断操作会针对特定时区执行;例如,截断到 day
会产生该时区午夜的值。默认情况下,截断是针对当前 TimeZone 设置执行的,但是可以提供可选的 time_zone
参数来指定不同的时区。时区名称可以使用 第 8.5.3 节 中描述的任何方式指定。
在处理 timestamp without time zone
或 interval
输入时,无法指定时区。这些始终按字面值处理。
示例(假设本地时区是 America/New_York
)
SELECT date_trunc('hour', TIMESTAMP '2001-02-16 20:38:40'); Result:2001-02-16 20:00:00
SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40'); Result:2001-01-01 00:00:00
SELECT date_trunc('day', TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40+00'); Result:2001-02-16 00:00:00-05
SELECT date_trunc('day', TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40+00', 'Australia/Sydney'); Result:2001-02-16 08:00:00-05
SELECT date_trunc('hour', INTERVAL '3 days 02:47:33'); Result:3 days 02:00:00
date_bin
#date_bin
函数将输入时间戳“分段”到指定的时间间隔(步长)中,并与指定的原点对齐。
date_bin(stride
,source
,origin
)
source
是一个类型为 timestamp
或 timestamp with time zone
的值表达式。(类型为 date
的值会自动转换为 timestamp
。)stride
是一个类型为 interval
的值表达式。返回值同样是 timestamp
或 timestamp with time zone
类型,它标记了将 source
放置到其中的时间段的开始。
示例
SELECT date_bin('15 minutes', TIMESTAMP '2020-02-11 15:44:17', TIMESTAMP '2001-01-01'); Result:2020-02-11 15:30:00
SELECT date_bin('15 minutes', TIMESTAMP '2020-02-11 15:44:17', TIMESTAMP '2001-01-01 00:02:30'); Result:2020-02-11 15:32:30
在完整单位(1 分钟、1 小时等)的情况下,它会产生与类似的 date_trunc
调用相同的结果,但不同之处在于 date_bin
可以截断到任意时间间隔。
stride
时间间隔必须大于零,并且不能包含月或更大的单位。
AT TIME ZONE and AT LOCAL
#AT TIME ZONE
运算符将时间戳无时区转换为/从时间戳有时区,以及将 time with time zone
值转换为不同的时区。 表 9.34 显示了它的变体。
表 9.34. AT TIME ZONE
和 AT LOCAL
变体
运算符 描述 示例 |
---|
将给定的时间戳无时区转换为时间戳有时区,假设给定值位于指定的时区中。
|
将给定的时间戳无时区转换为时间戳有时区,其中时区为会话的
|
将给定的时间戳有时区转换为时间戳无时区,如同该时间显示在该时区一样。
|
将给定的时间戳有时区转换为时间戳无时区,如同该时间显示在会话的
|
将给定的时间有时区转换为新的时区。由于未提供日期,因此这将使用当前活动 UTC 偏移量来处理指定的目的地时区。
|
将给定的时间有时区转换为新的时区。由于未提供日期,因此这将使用当前活动 UTC 偏移量来处理会话的 假设会话的
|
在这些表达式中,所需时区 zone
可以指定为文本值(例如,'America/Los_Angeles'
)或时间间隔(例如,INTERVAL '-08:00'
)。在文本情况下,时区名称可以使用 第 8.5.3 节 中描述的任何方式指定。时间间隔情况仅适用于与 UTC 有固定偏移量的时区,因此在实践中并不常见。
语法 AT LOCAL
可以用作 AT TIME ZONE
的简写,其中 local
local
是会话的 TimeZone
值。
示例(假设当前 TimeZone 设置为 America/Los_Angeles
)
SELECT TIMESTAMP '2001-02-16 20:38:40' AT TIME ZONE 'America/Denver'; Result:2001-02-16 19:38:40-08
SELECT TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-05' AT TIME ZONE 'America/Denver'; Result:2001-02-16 18:38:40
SELECT TIMESTAMP '2001-02-16 20:38:40' AT TIME ZONE 'Asia/Tokyo' AT TIME ZONE 'America/Chicago'; Result:2001-02-16 05:38:40
SELECT TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-05' AT LOCAL; Result:2001-02-16 17:38:40
SELECT TIME WITH TIME ZONE '20:38:40-05' AT LOCAL; Result:17:38:40
第一个示例将时区添加到缺少时区的数值,并使用当前的 TimeZone
设置显示该数值。第二个示例将时间戳有时区的值移到指定的时区,并返回无时区的值。这允许存储和显示与当前 TimeZone
设置不同的值。第三个示例将东京时间转换为芝加哥时间。第四个示例将时间戳有时区的值移到当前由 TimeZone
设置指定的时区,并返回无时区的值。
第五个示例是一个警示故事。由于输入值没有关联的日期,因此转换是使用会话的当前日期进行的。因此,此静态示例可能会显示错误的结果,具体取决于查看它的时间,因为 'America/Los_Angeles'
遵循夏令时。
函数等效于符合 SQL 的结构 timezone
(zone
, timestamp
)
。timestamp
AT TIME ZONE zone
函数等效于符合 SQL 的结构 timezone
(zone
, time
)
。time
AT TIME ZONE zone
函数等效于符合 SQL 的结构 timezone
(timestamp
)
。timestamp
AT LOCAL
函数等效于符合 SQL 的结构 timezone
(time
)
。time
AT LOCAL
PostgreSQL 提供了一些返回与当前日期和时间相关的值的函数。这些 SQL 标准函数返回的值都基于当前事务的开始时间。
CURRENT_DATE CURRENT_TIME CURRENT_TIMESTAMP CURRENT_TIME(precision
) CURRENT_TIMESTAMP(precision
) LOCALTIME LOCALTIMESTAMP LOCALTIME(precision
) LOCALTIMESTAMP(precision
)
CURRENT_TIME
和 CURRENT_TIMESTAMP
提供带时区的值;LOCALTIME
和 LOCALTIMESTAMP
提供无时区的值。
CURRENT_TIME
、CURRENT_TIMESTAMP
、LOCALTIME
和 LOCALTIMESTAMP
可以选择性地接受一个精度参数,这会导致结果在秒字段中舍入到小数点后指定的位数。如果没有精度参数,则会以可用精度提供结果。
一些示例
SELECT CURRENT_TIME; Result:14:39:53.662522-05
SELECT CURRENT_DATE; Result:2019-12-23
SELECT CURRENT_TIMESTAMP; Result:2019-12-23 14:39:53.662522-05
SELECT CURRENT_TIMESTAMP(2); Result:2019-12-23 14:39:53.66-05
SELECT LOCALTIMESTAMP; Result:2019-12-23 14:39:53.662522
由于这些函数返回当前事务的开始时间,因此它们的值在事务期间不会改变。这被认为是一个特性:目的是允许单个事务具有对“当前”时间的统一认识,以便同一事务中的多个修改具有相同的时间戳。
其他数据库系统可能会更频繁地更新这些值。
PostgreSQL 还提供了一些返回当前语句的开始时间以及调用函数时实际当前时间的函数。非 SQL 标准时间函数的完整列表是
transaction_timestamp() statement_timestamp() clock_timestamp() timeofday() now()
transaction_timestamp()
等效于 CURRENT_TIMESTAMP
,但它以更清晰的方式命名以反映它返回的内容。statement_timestamp()
返回当前语句的开始时间(更具体地说是从客户端接收最新命令消息的时间)。statement_timestamp()
和 transaction_timestamp()
在事务的第一个命令期间返回相同的值,但在后续命令期间可能不同。clock_timestamp()
返回实际的当前时间,因此它的值即使在单个 SQL 命令中也会改变。timeofday()
是一个历史上的 PostgreSQL 函数。与 clock_timestamp()
一样,它返回实际的当前时间,但以格式化的 text
字符串形式而不是 timestamp with time zone
值。now()
是 PostgreSQL 的传统函数,相当于 transaction_timestamp()
。
所有日期/时间数据类型也接受特殊字面值 now
来指定当前日期和时间(同样,解释为事务开始时间)。因此,以下三种都返回相同的结果
SELECT CURRENT_TIMESTAMP; SELECT now(); SELECT TIMESTAMP 'now'; -- but see tip below
在指定要稍后评估的值时,不要使用第三种形式,例如在表列的 DEFAULT
子句中。系统将在解析常量时立即将 now
转换为 timestamp
,因此在需要默认值时,将使用表创建的时间!前两种形式将不会在使用默认值之前进行评估,因为它们是函数调用。因此,它们将提供将默认值设置为插入行时间的预期行为。(另请参见 第 8.5.1.4 节。)
以下函数可用于延迟服务器进程的执行
pg_sleep (double precision
) pg_sleep_for (interval
) pg_sleep_until (timestamp with time zone
)
pg_sleep
使当前会话的进程休眠,直到经过给定的秒数。可以指定小数秒延迟。 pg_sleep_for
是一个便利函数,允许将休眠时间指定为 interval
。 pg_sleep_until
是一个便利函数,用于在需要特定唤醒时间时。例如
SELECT pg_sleep(1.5); SELECT pg_sleep_for('5 minutes'); SELECT pg_sleep_until('tomorrow 03:00');
休眠间隔的有效分辨率是特定于平台的;0.01 秒是一个常见的值。休眠延迟将至少与指定的时间一样长。它可能会根据服务器负载等因素而更长。特别是,pg_sleep_until
无法保证在指定的时间精确唤醒,但它不会早于指定的时间唤醒。
在调用 pg_sleep
或其变体时,请确保您的会话不会持有超过必要的锁。否则,其他会话可能需要等待您的休眠进程,从而减慢整个系统。
如果您在文档中看到任何不正确的内容,不符合您对特定功能的体验,或者需要进一步说明,请使用 此表格 报告文档问题。