2024年9月26日: PostgreSQL 17 发布!
支持的版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不支持的版本:11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

9.9. 日期/时间函数和运算符 #

表 9.33 显示了可用于日期/时间值处理的可用函数,详细信息在以下小节中给出。 表 9.32 说明了基本算术运算符(+* 等)的行为。有关格式化函数,请参阅 第 9.8 节。您应该熟悉来自 第 8.5 节 的日期/时间数据类型的背景信息。

此外,表 9.1 中显示的常用比较运算符可用于日期/时间类型。日期和时间戳(带或不带时区)都是可比较的,而时间(带或不带时区)和间隔只能与相同数据类型的其他值进行比较。当将不带时区的时间戳与带时区的时间戳进行比较时,假定前一个值以 TimeZone 配置参数指定的时区给出,并在与后一个值进行比较时旋转为 UTC(后一个值在内部已为 UTC)。类似地,当将日期值与时间戳进行比较时,假定日期值代表 TimeZone 时区的午夜。

以下所有接受 timetimestamp 输入的函数和运算符实际上都有两个变体:一个接受 time with time zonetimestamp with time zone,另一个接受 time without time zonetimestamp without time zone。为简洁起见,这些变体没有单独显示。此外,+* 运算符以可交换对的形式出现(例如,date + integerinteger + date);我们只显示其中之一。

表 9.32. 日期/时间运算符

运算符

描述

示例

date + integerdate

将一定数量的天数加到日期

date '2001-09-28' + 72001-10-05

date + intervaltimestamp

将一个间隔加到日期

date '2001-09-28' + interval '1 hour'2001-09-28 01:00:00

date + timetimestamp

将一天中的时间加到日期

date '2001-09-28' + time '03:00'2001-09-28 03:00:00

interval + intervalinterval

加间隔

interval '1 day' + interval '1 hour'1 day 01:00:00

timestamp + intervaltimestamp

将一个间隔加到时间戳

timestamp '2001-09-28 01:00' + interval '23 hours'2001-09-29 00:00:00

time + intervaltime

将一个间隔加到时间

time '01:00' + interval '3 hours'04:00:00

- intervalinterval

取一个间隔的负值

- interval '23 hours'-23:00:00

date - dateinteger

减去日期,产生经过的天数

date '2001-10-01' - date '2001-09-28'3

date - integerdate

从日期中减去一定数量的天数

date '2001-10-01' - 72001-09-24

date - intervaltimestamp

从日期中减去一个间隔

date '2001-09-28' - interval '1 hour'2001-09-27 23:00:00

time - timeinterval

减去时间

time '05:00' - time '03:00'02:00:00

time - intervaltime

从时间中减去一个间隔

time '05:00' - interval '2 hours'03:00:00

timestamp - intervaltimestamp

从时间戳中减去一个间隔

timestamp '2001-09-28 23:00' - interval '23 hours'2001-09-28 00:00:00

interval - intervalinterval

减去间隔

interval '1 day' - interval '1 hour'1 day -01:00:00

timestamp - timestampinterval

减去时间戳(将 24 小时间隔转换为天,类似于 justify_hours())

timestamp '2001-09-29 03:00' - timestamp '2001-07-27 12:00'63 days 15:00:00

interval * double precisioninterval

将一个间隔乘以一个标量

interval '1 second' * 90000:15:00

interval '1 day' * 2121 days

interval '1 hour' * 3.503:30:00

interval / double precisioninterval

将一个间隔除以一个标量

interval '1 hour' / 1.500:40:00


表 9.33. 日期/时间函数

函数

描述

示例

age ( timestamp, timestamp ) → interval

减去参数,产生一个符号结果,它使用年份和月份,而不是仅仅使用天数

age(timestamp '2001-04-10', timestamp '1957-06-13')43 years 9 mons 27 days

age ( timestamp ) → interval

current_date(午夜)减去参数

age(timestamp '1957-06-13')62 years 6 mons 10 days

clock_timestamp ( ) → timestamp with time zone

当前日期和时间(在语句执行期间更改);见 第 9.9.5 节

clock_timestamp()2019-12-23 14:39:53.662522-05

current_datedate

当前日期;见 第 9.9.5 节

current_date2019-12-23

current_timetime with time zone

当前时间;参见 第 9.9.5 节

current_time14:39:53.662522-05

current_time ( integer ) → 带时区的时间

当前时间,精度有限;参见 第 9.9.5 节

current_time(2)14:39:53.66-05

current_timestamp带时区的 timestamp

当前日期和时间(当前事务开始时间);参见 第 9.9.5 节

current_timestamp2019-12-23 14:39:53.662522-05

current_timestamp ( integer ) → 带时区的 timestamp

当前日期和时间(当前事务开始时间),精度有限;参见 第 9.9.5 节

current_timestamp(0)2019-12-23 14:39:53-05

date_add ( 带时区的 timestamp, interval [, text ] ) → 带时区的 timestamp

将一个 interval 添加到一个 带时区的 timestamp,根据第三个参数指定的时区计算时间和夏令时调整,或者如果省略则使用当前的 TimeZone 设置。带有两个参数的形式等效于 带时区的 timestamp + interval 运算符。

date_add('2021-10-31 00:00:00+02'::timestamptz, '1 day'::interval, 'Europe/Warsaw')2021-10-31 23:00:00+00

date_bin ( interval, timestamp, timestamp ) → timestamp

将输入分箱到以指定原点对齐的指定间隔;参见 第 9.9.3 节

date_bin('15 minutes', timestamp '2001-02-16 20:38:40', timestamp '2001-02-16 20:05:00')2001-02-16 20:35:00

date_part ( text, timestamp ) → double precision

获取 timestamp 子字段(等效于 extract);参见 第 9.9.1 节

date_part('hour', timestamp '2001-02-16 20:38:40')20

date_part ( text, interval ) → double precision

获取 interval 子字段(等效于 extract);参见 第 9.9.1 节

date_part('month', interval '2 years 3 months')3

date_subtract ( 带时区的 timestamp, interval [, text ] ) → 带时区的 timestamp

带时区的 timestamp 中减去一个 interval,根据第三个参数指定的时区计算时间和夏令时调整,或者如果省略则使用当前的 TimeZone 设置。带有两个参数的形式等效于 带时区的 timestamp - interval 运算符。

date_subtract('2021-11-01 00:00:00+01'::timestamptz, '1 day'::interval, 'Europe/Warsaw')2021-10-30 22:00:00+00

date_trunc ( text, timestamp ) → timestamp

截断到指定精度;参见 第 9.9.2 节

date_trunc('hour', timestamp '2001-02-16 20:38:40')2001-02-16 20:00:00

date_trunc ( text, 带时区的 timestamp, text ) → 带时区的 timestamp

在指定时区中截断到指定精度;参见 第 9.9.2 节

date_trunc('day', timestamptz '2001-02-16 20:38:40+00', 'Australia/Sydney')2001-02-16 13:00:00+00

date_trunc ( text, interval ) → interval

截断到指定精度;参见 第 9.9.2 节

date_trunc('hour', interval '2 days 3 hours 40 minutes')2 days 03:00:00

extract ( field from timestamp ) → numeric

获取 timestamp 子字段;参见 第 9.9.1 节

extract(hour from timestamp '2001-02-16 20:38:40')20

extract ( field from interval ) → numeric

获取 interval 子字段;参见 第 9.9.1 节

extract(month from interval '2 years 3 months')3

isfinite ( date ) → boolean

测试日期是否有限(非 +/-infinity)

isfinite(date '2001-02-16')true

isfinite ( timestamp ) → boolean

测试 timestamp 是否有限(非 +/-infinity)

isfinite(timestamp 'infinity')false

isfinite ( interval ) → boolean

测试 interval 是否有限(非 +/-infinity)

isfinite(interval '4 hours')true

justify_days ( interval ) → interval

调整间隔,将 30 天时间段转换为月

justify_days(interval '1 year 65 days')1 year 2 mons 5 days

justify_hours ( interval ) → interval

调整间隔,将 24 小时时间段转换为天

justify_hours(interval '50 hours 10 minutes')2 days 02:10:00

justify_interval ( interval ) → interval

使用 justify_daysjustify_hours 调整间隔,并进行额外的符号调整

justify_interval(interval '1 mon -1 hour')29 days 23:00:00

localtimetime

当前时间;参见 第 9.9.5 节

localtime14:39:53.662522

localtime ( integer ) → time

当前时间,精度有限;参见 第 9.9.5 节

localtime(0)14:39:53

localtimestamptimestamp

当前日期和时间(当前事务开始时间);参见 第 9.9.5 节

localtimestamp2019-12-23 14:39:53.662522

localtimestamp ( integer ) → timestamp

当前日期和时间(当前事务开始时间),精度有限;参见 第 9.9.5 节

localtimestamp(2)2019-12-23 14:39:53.66

make_date ( year int, month int, day int ) → date

从年份、月份和日期字段创建日期(负年份表示公元前)

make_date(2013, 7, 15)2013-07-15

make_interval ( [ years int [, months int [, weeks int [, days int [, hours int [, mins int [, secs double precision ]]]]]]] ) → interval

从年份、月份、周、天、小时、分钟和秒字段创建间隔,这些字段都可以默认为零

make_interval(days => 10)10 days

make_time ( hour int, min int, sec double precision ) → time

从小时、分钟和秒字段创建时间

make_time(8, 15, 23.5)08:15:23.5

make_timestamp ( year int, month int, day int, hour int, min int, sec double precision ) → timestamp

从年份、月份、日期、小时、分钟和秒字段创建 timestamp(负年份表示公元前)

make_timestamp(2013, 7, 15, 8, 15, 23.5)2013-07-15 08:15:23.5

make_timestamptz ( year int, month int, day int, hour int, min int, sec double precision [, timezone text ] ) → 带时区的 timestamp

从年份、月份、日期、小时、分钟和秒字段创建带时区的 timestamp(负年份表示公元前)。如果未指定 timezone,则使用当前时区;这些示例假设会话时区为 Europe/London

make_timestamptz(2013, 7, 15, 8, 15, 23.5)2013-07-15 08:15:23.5+01

make_timestamptz(2013, 7, 15, 8, 15, 23.5, 'America/New_York')2013-07-15 13:15:23.5+01

now ( ) → 带时区的 timestamp

当前日期和时间(当前事务开始时间);参见 第 9.9.5 节

now()2019-12-23 14:39:53.662522-05

statement_timestamp ( ) → 带时区的 timestamp

当前日期和时间(当前语句开始时间);参见 第 9.9.5 节

statement_timestamp()2019-12-23 14:39:53.662522-05

timeofday ( ) → text

当前日期和时间(类似于 clock_timestamp,但作为 text 字符串);参见 第 9.9.5 节

timeofday()Mon Dec 23 14:39:53.662522 2019 EST

transaction_timestamp ( ) → timestamp with time zone

当前日期和时间(当前事务开始时间);参见 第 9.9.5 节

transaction_timestamp()2019-12-23 14:39:53.662522-05

to_timestamp ( double precision ) → timestamp with time zone

将 Unix 纪元(自 1970-01-01 00:00:00+00 起的秒数)转换为带时区的时间戳

to_timestamp(1284352323)2010-09-13 04:32:03+00


除此之外,SQL OVERLAPS 运算符也受支持

(start1, end1) OVERLAPS (start2, end2)
(start1, length1) OVERLAPS (start2, length2)

当两个时间段(由其端点定义)重叠时,此表达式返回真值,当它们不重叠时,返回假值。端点可以指定为日期、时间或时间戳对;或作为日期、时间或时间戳,后跟一个时间间隔。当提供一对值时,可以先写开始或结束;OVERLAPS 自动将对中的较早值视为开始。每个时间段都被认为代表半开区间 start <= time < end,除非 startend 相等,在这种情况下,它表示该单个时间点。这意味着例如,只有公共端点的两个时间段不会重叠。

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 值添加到(或从 timestamptimestamp 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

9.9.1. EXTRACT, date_part #

EXTRACT(field FROM source)

extract 函数从日期/时间值中检索子字段,例如年或小时。 source 必须是类型为 timestampdatetimeinterval 的值表达式。(时间戳和时间可以有或没有时区。) 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 起的秒数(对于该日期之前的时间戳为负);对于 datetimestamp 值,自 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 应用于从 datetimestamp 值中提取的纪元可能会产生误导性的结果:结果将有效地假定原始值以 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 输入,epochjulianyearisoyeardecadecenturymillennium;对于 interval 输入,epochhourdayyeardecadecenturymillennium)。对于其他字段,则返回 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

9.9.2. date_trunc #

date_trunc 函数在概念上类似于数字的 trunc 函数。

date_trunc(field, source [, time_zone ])

source 是一个类型为 timestamptimestamp with time zoneinterval 的值表达式。(类型为 datetime 的值会自动分别转换为 timestampinterval。)field 选择将输入值截断到哪个精度。返回值同样是 timestamptimestamp with time zoneinterval 类型,并且它将所有小于所选字段的字段设置为零(或对于天和月,设置为一)。

有效的 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 zoneinterval 输入时,无法指定时区。这些始终按字面值处理。

示例(假设本地时区是 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

9.9.3. date_bin #

date_bin 函数将输入时间戳“分段”到指定的时间间隔(步长)中,并与指定的原点对齐。

date_bin(stride, source, origin)

source 是一个类型为 timestamptimestamp with time zone 的值表达式。(类型为 date 的值会自动转换为 timestamp。)stride 是一个类型为 interval 的值表达式。返回值同样是 timestamptimestamp 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 时间间隔必须大于零,并且不能包含月或更大的单位。

9.9.4. AT TIME ZONE and AT LOCAL #

AT TIME ZONE 运算符将时间戳时区转换为/从时间戳时区,以及将 time with time zone 值转换为不同的时区。 表 9.34 显示了它的变体。

表 9.34. AT TIME ZONEAT LOCAL 变体

运算符

描述

示例

timestamp without time zone AT TIME ZONE zonetimestamp with time zone

将给定的时间戳时区转换为时间戳时区,假设给定值位于指定的时区中。

timestamp '2001-02-16 20:38:40' at time zone 'America/Denver'2001-02-17 03:38:40+00

timestamp without time zone AT LOCALtimestamp with time zone

将给定的时间戳时区转换为时间戳时区,其中时区为会话的 TimeZone 值。

timestamp '2001-02-16 20:38:40' at local2001-02-17 03:38:40+00

timestamp with time zone AT TIME ZONE zonetimestamp without time zone

将给定的时间戳时区转换为时间戳时区,如同该时间显示在该时区一样。

timestamp with time zone '2001-02-16 20:38:40-05' at time zone 'America/Denver'2001-02-16 18:38:40

timestamp with time zone AT LOCALtimestamp without time zone

将给定的时间戳时区转换为时间戳时区,如同该时间显示在会话的 TimeZone 值所代表的时区一样。

timestamp with time zone '2001-02-16 20:38:40-05' at local2001-02-16 18:38:40

time with time zone AT TIME ZONE zonetime with time zone

将给定的时间时区转换为新的时区。由于未提供日期,因此这将使用当前活动 UTC 偏移量来处理指定的目的地时区。

time with time zone '05:34:17-05' at time zone 'UTC'10:34:17+00

time with time zone AT LOCALtime with time zone

将给定的时间时区转换为新的时区。由于未提供日期,因此这将使用当前活动 UTC 偏移量来处理会话的 TimeZone 值。

假设会话的 TimeZone 设置为 UTC

time with time zone '05:34:17-05' at local10:34:17+00


在这些表达式中,所需时区 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' 遵循夏令时。

timezone(zone, timestamp) 函数等效于符合 SQL 的结构 timestamp AT TIME ZONE zone

timezone(zone, time) 函数等效于符合 SQL 的结构 time AT TIME ZONE zone

timezone(timestamp) 函数等效于符合 SQL 的结构 timestamp AT LOCAL

timezone(time) 函数等效于符合 SQL 的结构 time AT LOCAL

9.9.5. 当前日期/时间 #

PostgreSQL 提供了一些返回与当前日期和时间相关的值的函数。这些 SQL 标准函数返回的值都基于当前事务的开始时间。

CURRENT_DATE
CURRENT_TIME
CURRENT_TIMESTAMP
CURRENT_TIME(precision)
CURRENT_TIMESTAMP(precision)
LOCALTIME
LOCALTIMESTAMP
LOCALTIME(precision)
LOCALTIMESTAMP(precision)

CURRENT_TIMECURRENT_TIMESTAMP 提供带时区的值;LOCALTIMELOCALTIMESTAMP 提供无时区的值。

CURRENT_TIMECURRENT_TIMESTAMPLOCALTIMELOCALTIMESTAMP 可以选择性地接受一个精度参数,这会导致结果在秒字段中舍入到小数点后指定的位数。如果没有精度参数,则会以可用精度提供结果。

一些示例

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 节。)

9.9.6. 延迟执行 #

以下函数可用于延迟服务器进程的执行

pg_sleep ( double precision )
pg_sleep_for ( interval )
pg_sleep_until ( timestamp with time zone )

pg_sleep 使当前会话的进程休眠,直到经过给定的秒数。可以指定小数秒延迟。 pg_sleep_for 是一个便利函数,允许将休眠时间指定为 intervalpg_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 或其变体时,请确保您的会话不会持有超过必要的锁。否则,其他会话可能需要等待您的休眠进程,从而减慢整个系统。

提交更正

如果您在文档中看到任何不正确的内容,不符合您对特定功能的体验,或者需要进一步说明,请使用 此表格 报告文档问题。