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

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

9.9.1. EXTRACTdate_part
9.9.2. date_trunc
9.9.3. date_bin
9.9.4. AT TIME ZONE
9.9.5. 当前日期/时间
9.9.6. 延迟执行

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

此外,表 9.1 中显示的常用比较运算符可用于日期/时间类型。日期和时间戳(带或不带时区)都是可比较的,而时间(带或不带时区)和间隔只能与相同数据类型的其他值进行比较。将不带时区的 time 戳与带时区的 time 戳进行比较时,前者值被假定为由 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

从时间中减去一个时间间隔

时间 '05:00' - 时间间隔 '2 小时'03:00:00

时间戳 - 时间间隔时间戳

从时间戳中减去一个时间间隔

时间戳 '2001-09-28 23:00' - 时间间隔 '23 小时'2001-09-28 00:00:00

时间间隔 - 时间间隔时间间隔

减去时间间隔

时间间隔 '1 天' - 时间间隔 '1 小时'1 天 -01:00:00

时间戳 - 时间戳时间间隔

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

时间戳 '2001-09-29 03:00' - 时间戳 '2001-07-27 12:00'63 天 15:00:00

时间间隔 * 双精度时间间隔

将时间间隔乘以一个标量

时间间隔 '1 秒' * 90000:15:00

时间间隔 '1 天' * 2121 天

时间间隔 '1 小时' * 3.503:30:00

时间间隔 / 双精度时间间隔

将时间间隔除以一个标量

时间间隔 '1 小时' / 1.500:40:00


表 9.33 日期/时间函数

函数

说明

示例

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

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

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

age ( 时间戳 ) → 时间间隔

current_date(午夜)减去参数

age(时间戳 '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带时区的 time

一天中的当前时间;请参见 第 9.9.5 节

current_time14:39:53.662522-05

current_time ( integer ) → 带时区的 time

一天中的当前时间,精度有限;请参见 第 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

获取时间戳子字段(等效于 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 ( timestamp with time zone, interval [, text ] ) → timestamp with time zone

timestamp with time zone 中减去一个 interval,根据第三个参数指定的时区计算一天中的时间和夏令时调整,如果省略,则使用当前 TimeZone 设置。带有两个参数的形式等效于 timestamp with time zone - 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 with time zone, text ) → timestamp with time zone

在指定时区截断到指定精度;请参见 第 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

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

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

extract ( field from interval ) → numeric

获取间隔子字段;请参阅 第 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 '35 days')1 mon 5 days

justify_hours ( interval ) → interval

调整间隔,以便将 24 小时的时间段表示为天

justify_hours(interval '27 hours')1 day 03:00: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

当前日期和时间(当前事务开始时间);请参见 第 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 ( ) → 文本

当前日期和时间(如同clock_timestamp,但作为text字符串);请参阅第 9.9.5 节

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

transaction_timestamp ( ) → 带时区的 timestamp

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

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

to_timestamp ( 双精度 ) → 带时区的 timestamp

将 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)

当两个时间段(由其端点定义)重叠时,此表达式返回真,不重叠时返回假。端点可以指定为日期、时间或时间戳对;或者作为日期、时间或时间戳,后跟一个间隔。当提供一对值时,可以先写开始或结束;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

当向 timestamptimestamp with time zone 值添加 interval 值(或从 interval 值中减去 interval 值)时,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

9.9.1. EXTRACTdate_part #

EXTRACT(field FROM source)

extract 函数从日期/时间值中检索子字段,例如年份或小时。 source 必须是 timestamptimeinterval 类型的值表达式。(date 类型的表达式会被强制转换为 timestamp,因此也可以使用。) field 是一个标识符或字符串,用于选择从源值中提取哪个字段。 extract 函数返回 numeric 类型的值。以下字段名称有效

century

世纪

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

第一个世纪始于公元 0001-01-01 00:00:00,尽管他们当时并不知道。此定义适用于所有格里高利历国家/地区。没有世纪数 0,您从 -1 世纪到 1 世纪。如果您不同意这一点,请将您的投诉写给:教皇,罗马圣彼得大教堂,梵蒂冈。

day

对于 timestamp 值,日期(本月)字段 (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 起的秒数(该时间之前的 timestamp 为负值);对于 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 相同。这与 ISO 8601 星期几编号相匹配。

isoyear

日期所在的 ISO 8601 周编号年(不适用于间隔)

SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-01');
Result: 2005
SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-02');
Result: 2006

每个 ISO 8601 周编号年都从包含 1 月 4 日的星期一的星期开始,因此在 1 月初或 12 月末,ISO 年可能与公历年不同。有关更多信息,请参见 week 字段。

此字段在 8.3 之前的 PostgreSQL 版本中不可用。

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

千年

SELECT EXTRACT(MILLENNIUM FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 3

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

对于 timestamp 值,年份中的月份数 (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
时区

以秒为单位衡量的 UTC 时区偏移量。正值对应于 UTC 以东的时区,负值对应于 UTC 以西的时区。(从技术上讲,PostgreSQL 不使用 UTC,因为不处理闰秒。)

timezone_hour

时区偏移量的小时部分

timezone_minute

时区偏移量的分钟部分

ISO 8601 年份的周数。根据定义,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,因此应谨慎地从 AD 年中减去 BC 年。

SELECT EXTRACT(YEAR FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 2001

注意

当输入值为 +/-Infinity 时,extract 会为单调递增字段(epochjulianyearisoyeardecadecenturymillennium)返回 +/-Infinity。对于其他字段,返回 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
month
quarter
decade
century
millennium

当输入值类型为 带时区的 timestamp 时,截断相对于特定时区执行;例如,截断到 day 会生成该时区午夜的值。默认情况下,截断相对于当前 时区 设置执行,但可以提供可选 time_zone 参数来指定不同的时区。时区名称可以用 第 8.5.3 节 中描述的任何方式指定。

处理 不带时区的 timestampinterval 输入时,无法指定时区。这些始终按面值获取。

示例(假设本地时区为 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 是类型为 timestamp带时区的 timestamp 的值表达式。(类型为 date 的值会自动转换为 timestamp。)stride 是类型为 interval 的值表达式。返回值的类型同样为 timestamp带时区的 timestamp,并且它标记了 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 #

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

表 9.34. AT TIME ZONE 变体

运算符

说明

示例

timestamp without time zone AT TIME ZONE zonetimestamp with time zone

将给定的 不带 时区的 time stamp 转换为 时区的 time stamp,假设给定值位于指定的时区。

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

timestamp with time zone AT TIME ZONE zonetimestamp without time zone

将给定的 时区的 time stamp 转换为 不带 时区的 time stamp,因为时间将显示在该时区中。

timestamp with time zone '2001-02-16 20:38:40-05' at time zone 'America/Denver'2001-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


在这些表达式中,所需的时区 zone 可以指定为文本值(例如,'America/Los_Angeles')或间隔(例如,INTERVAL '-08:00')。在文本情况下,可以在 第 8.5.3 节 中描述的任何方式中指定时区名称。间隔情况仅适用于与 UTC 有固定偏移的时区,因此在实践中并不常见。

示例(假设当前 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

第一个示例向缺乏时区的 value 添加时区,并使用当前 TimeZone 设置显示 value。第二个示例将带时区的 time stamp 值移至指定的时区,并返回不带时区的 value。这允许存储和显示不同于当前 TimeZone 设置的值。第三个示例将东京时间转换为芝加哥时间。

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

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()PostgreSQLtransaction_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 或其变体时,确保会话不持有比必要更多的锁。否则,其他会话可能必须等待正在休眠的进程,从而导致整个系统速度变慢。