Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17

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

9.9.1. EXTRACT, date_part
9.9.2. date_trunc
9.9.3. date_bin
9.9.4. AT TIME ZONE 和 AT LOCAL
9.9.5. 当前日期/时间
9.9.6. 延迟执行

表 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 '2001-09-28' + time '03:00'2001-09-28 03:00:00

间隔 + 间隔间隔

添加间隔

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

时间戳 + 间隔时间戳

在时间戳中添加间隔

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

时间 + 间隔时间

在时间中添加间隔

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

- 间隔间隔

否定间隔

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

日期 - 日期整数

减去日期,得出已过天数

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

日期 - 整数日期

从日期中减去一些天数

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

日期 - 间隔时间戳

从日期中减去间隔

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

时间 - 时间间隔

减去时间

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

时间 - 间隔时间

从时间中减去间隔

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

时间戳 - 间隔时间戳

从时间戳中减去间隔

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

间隔 - 间隔间隔

减去间隔

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

时间戳 - 时间戳区间

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

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

区间 * 双精度区间

使用标量乘以区间

interval '1 second' * 90000:15:00

interval '1 day' * 2121 天

interval '1 hour' * 3.503:30:00

区间 / 双精度区间

使用标量除以区间

interval '1 hour' / 1.500:40:00


表 9.33。日期/时间函数

函数

说明

示例

age ( 时间戳, 时间戳 ) → 区间

减去参数,生成“符号”结果,使用年和月,而不仅仅是天

age(timestamp '2001-04-10', timestamp '1957-06-13')43 年 9 个月 27 天

age ( 时间戳 ) → 区间

current_date(午夜)减去参数

age(timestamp '1957-06-13')62 年 6 个月 10 天

clock_timestamp ( ) → 时间戳带时区

当前日期和时间(在语句执行过程中发生变化);请参见 第 9.9.5 节

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

current_date日期

当前日期;请参见 第 9.9.5 节

current_date2019-12-23

current_time时间带时区

当前时间;请参见 第 9.9.5 节

current_time14:39:53.662522-05

current_time ( 整数 ) → 时间带时区

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

current_time(2)14:39:53.66-05

current_timestamptimestamp with time zone

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

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

current_timestamp ( integer ) → timestamp with time zone

当前日期和时间(当前事务开始时间),使用小数精度;参见 9.9.5 节

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

date_add ( timestamp with time zone, interval [, text ] ) → timestamp with time zone

interval 添加 timestamp with time zone,根据第三个参数指定的时区计算一天中的时间和日光节约调整,或者如果省略该参数,则计算当前 TimeZone 设置。使用两个参数的形式相当于 timestamp with time zone + 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

获取时间戳子字段(等效于 extract);参见 9.9.1 节

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

date_part ( text, interval ) → double precision

获取区间子字段(等同于 extract);请参阅 第 9.9.1 节

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

date_subtract ( 带时区时间戳, 区间 [, 文本 ] ) → 带时区时间戳

带时区时间戳中减去一个 区间,根据第三个参数中指定的时区或在省略该参数时当前 TimeZone 设置来计算一天中的时间和日光节约时调整。带有两个参数的形式等同于 带时区时间戳 - 区间 运算符。

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

date_trunc ( 文本, 时间戳 ) → 时间戳

截断至指定精度;请参阅 第 9.9.2 节

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

date_trunc ( 文本, 带时区时间戳, 文本 ) → 带时区时间戳

在指定时区截断至指定精度;请参阅 第 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 ( 文本, 区间 ) → 区间

截断至指定精度;请参阅 第 9.9.2 节

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

extract ( field from 时间戳 ) → 数值

获取时间戳子字段;请参阅 第 9.9.1 节

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

extract ( field from 区间 ) → 数值

获取区间子字段;请参阅 第 9.9.1 节

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

isfinite ( date ) → boolean

测试有限日期(非 +/- 无限大)

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

isfinite ( timestamp ) → boolean

测试有限时间戳(非 +/- 无限大)

isfinite(timestamp 'infinity')false

isfinite ( interval ) → boolean

测试有限间隔(非 +/- 无限大)

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

根据年、月、日、时、分、秒字段创建时间戳(负年表示公元前)

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 with time zone

从年、月、日、小时、分钟和秒字段创建带有时区的 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 with time zone

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

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

statement_timestamp() → timestamp with time zone

当前日期和时间(当前语句的开始);参见小节 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 起的秒数)转换为带有时区的 timestamp

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


除了这些函数,还支持 SQL OVERLAPS 运算符

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

当两个时间段(由其端点定义)重叠时,此表达式返回 true,而当它们不重叠时,此表达式返回 false。端点可以指定为日期对、时间或时间戳对;或者为一个日期、时间或时间戳后跟一个时间间隔。当提供一对儿值时,可以先写开始时间或结束时间;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 日。)然后天数字段会将时间戳的日期按指示的天数前进或后退。在这两个步骤中,都会保持当地的每日时间不变。最后,如果存在非零微秒字段,则会将其加或减为原文值。对识别夏令时的时区中的 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/Denver2005-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 将 epoch 值转换回 timestamp with time zone

SELECT to_timestamp(982384720.12);
Result: 2001-02-17 04:38:40.12+00

须注意,将 to_timestamp 应用于从 datetimestamp 值中提取的 epoch 值可能产生误导性结果:结果将有效地假定原始值已在 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 周编号系统中,年初日期可能属于前一年的第 52 周或第 53 周,而年末日期可能属于下一年的第一周。例如,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 年,因此在 公元年中减去 公元前年时应小心。

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

注意

当输入值是 +/- 无穷大时,extract 返回单调增加的字段(对于 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,它具有所有低于所选字段且设置位零(或对于 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 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 间隔必须大于零,且不能包含 month 或更大的单位。

9.9.4. AT TIME ZONE 和 AT LOCAL #

AT TIME ZONE 运算符将没有时区的 time stamp 转换为时区的 timestamp,并将 time with time zone 值转换为不同的时区。 表 9.34 显示其变体。

表 9.34.  AT TIME ZONEAT LOCAL 变体

运算符

说明

示例

timestamp without time zone AT TIME ZONE zonetimestamp with time zone

将给定的没有时区的 timestamp 转换为时区的 timestamp,假设给定值处于命名时区中。

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

将给定的没有时区的 timestamp 转换为会话 TimeZone 值作为时区的 timestamp。

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 转换为没有时区的 timestamp,因为时间显示在该时区内。

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

将给定的时区的 timestamp 转换为没有时区的 timestamp,因为时间显示在以会话 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

将给定时区的 time 转换为新的时区。由于未提供日期,这将使用命名的目标时区的当前有效的 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

将给定时间 使用 时区转换为一个新时区。由于没有提供日期,这使用会话的 TimeZone 值的当前活动 UTC 偏移。

假设会话的 TimeZone 设置为 UTC

本地时间为“05:34:17-05”的时间10: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 值。 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 是一个便利函数,允许将休眠时间指定为 间隔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 或其变量时,请确保您的会话未保持太多锁。否则,其他会话可能不得不等待您休眠的进程,从而使整个系统变慢。