表 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 节
|
获取时间戳子字段(等效于
|
获取间隔子字段(等效于
|
从
|
截断到指定的精度;参阅第 9.9.2 节
|
在指定的时区中截断到指定的精度;参阅第 9.9.2 节
|
截断到指定的精度;参阅第 9.9.2 节
|
获取时间戳子字段;参阅第 9.9.1 节
|
获取间隔子字段;参阅第 9.9.1 节
|
测试日期是否有限(不是 +/- 无穷大)
|
测试时间戳是否有限(不是 +/- 无穷大)
|
测试间隔是否有限(不是 +/- 无穷大)
|
调整间隔,将 30 天的时间段转换为月份
|
调整间隔,将 24 小时的时间段转换为天
|
使用
|
当前时间;参阅第 9.9.5 节
|
当前时间,精度有限;参阅第 9.9.5 节
|
当前日期和时间(当前事务的开始);参阅第 9.9.5 节
|
当前日期和时间(当前事务的开始),精度有限;参阅第 9.9.5 节
|
从年、月和日字段创建日期(负数年份表示公元前)
|
从年、月、周、日、小时、分钟和秒字段创建间隔,每个字段的默认值为零
|
从小时、分钟和秒字段创建时间
|
从年、月、日、小时、分钟和秒字段创建时间戳(负数年份表示公元前)
|
从年、月、日、小时、分钟和秒字段创建带时区的时间戳(负数年份表示公元前)。 如果未指定
|
当前日期和时间(当前事务的开始);参阅第 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
)
当两个时间段(由其端点定义)重叠时,此表达式产生 true,不重叠时产生 false。 端点可以指定为日期、时间或时间戳对;或者指定为日期、时间或时间戳后跟一个时间间隔。 当提供一对值时,可以先写入起始值或结束值;OVERLAPS
会自动将这对值中较早的值作为起始值。 除非 start
和 end
相等,在这种情况下它表示该单个时间点,否则每个时间段都视为表示半开区间 start
<=
time
<
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
值的月份、天数和微秒字段。 首先,非零月份字段会将时间戳的日期提前或减去指示的月份数,保持月份中的日期相同,除非它会超过新月份的末尾,在这种情况下,将使用该月份的最后一天。(例如,3 月 31 日加上 1 个月变为 4 月 30 日,但 3 月 31 日加上 2 个月变为 5 月 31 日。)然后,天数字段会将时间戳的日期提前或减去指示的天数。在这两个步骤中,本地时间都保持不变。最后,如果存在非零的微秒字段,则会按字面意义添加或减去。当在识别 DST 的时区对 timestamp with time zone
值执行算术运算时,这意味着添加或减去(比如)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
年
年份字段。请记住,没有公元 0
年,因此从公元 AD
年份中减去公元前 BC
年份时应谨慎。
SELECT EXTRACT(YEAR FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 2001
当处理 interval
值时,extract
函数生成与 interval 输出函数使用的解释相匹配的字段值。如果从一个非标准化的 interval 表示形式开始,这可能会产生令人惊讶的结果,例如
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。PostgreSQL 9.6 之前的版本对于无限输入的所有情况都返回零。
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
类型,并且它将所有小于所选字段的字段设置为零(对于 day 和 month,则设置为一)。
field
的有效值为
microseconds |
milliseconds |
second |
minute |
hour |
day |
week |
month |
quarter |
年 |
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 和 AT LOCAL
#AT TIME ZONE
运算符将不带时区的时间戳转换为带时区的时间戳,反之亦然,并将带时区的 time
值转换为不同的时区。 表 9.34 显示了其变体。
表 9.34. AT TIME ZONE
和 AT LOCAL
变体
操作符 描述 示例 |
---|
将给定的不带时区的时间戳转换为带时区的时间戳,假设给定值位于指定的时区中。
|
将给定的不带时区的时间戳转换为带有时区的时间戳,时区为会话的
|
将给定的带时区的时间戳转换为不带时区的时间戳,其时间将显示在该时区中。
|
将给定的带时区的时间戳转换为不带时区的时间戳,其时间将显示为会话的
|
将给定的带时区的时间转换为新的时区。由于没有提供日期,因此这将使用命名目标时区当前活动的 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
或其变体时,请确保您的会话持有的锁不超过必要的数量。否则,其他会话可能必须等待您休眠的进程,从而减慢整个系统的速度。
如果您在文档中看到任何不正确、与您特定功能的体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。