pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
表 9.28展示了可用于处理日期/时间值的函数,其细节在随后的小节中描述。表 9.27演示了基本算术操作符 (+、*等)的行为。 而与格式化相关的函数,可以参考第 9.8 节。你应当熟悉第 8.5 节中的日期/时间数据类型的背景知识。
所有下文描述的接受time或timestamp输入的函数和操作符实际上都有两种变体: 一种接收time with time zone或timestamp with time zone, 另外一种接受time without time zone或者 timestamp without time zone。 为了简化,这些变种没有被独立地展示。 此外,+和*操作符都是可交换的操作符对(例如,date + integer 和 integer + date);我们只显示每一对中的一个。
表 9.27. 日期/时间操作符
| Operator | 示例 | Result |
|---|---|---|
+ |
date '2001-09-28' + integer '7' |
date '2001-10-05' |
+ |
date '2001-09-28' + interval '1 hour' |
timestamp '2001-09-28 01:00:00' |
+ |
date '2001-09-28' + time '03:00' |
timestamp '2001-09-28 03:00:00' |
+ |
interval '1 day' + interval '1 hour' |
interval '1 day 01:00:00' |
+ |
timestamp '2001-09-28 01:00' + interval '23 hours' |
timestamp '2001-09-29 00:00:00' |
+ |
time '01:00' + interval '3 hours' |
time '04:00:00' |
- |
- interval '23 hours' |
interval '-23:00:00' |
- |
date '2001-10-01' - date '2001-09-28' |
integer '3' (days) |
- |
date '2001-10-01' - integer '7' |
date '2001-09-24' |
- |
date '2001-09-28' - interval '1 hour' |
timestamp '2001-09-27 23:00:00' |
- |
time '05:00' - time '03:00' |
interval '02:00:00' |
- |
time '05:00' - interval '2 hours' |
time '03:00:00' |
- |
timestamp '2001-09-28 23:00' - interval '23 hours' |
timestamp '2001-09-28 00:00:00' |
- |
interval '1 day' - interval '1 hour' |
interval '1 day -01:00:00' |
- |
timestamp '2001-09-29 03:00' - timestamp '2001-09-27 12:00' |
interval '1 day 15:00:00' |
* |
900 * interval '1 second' |
interval '00:15:00' |
* |
21 * interval '1 day' |
interval '21 days' |
* |
double precision '3.5' * interval '1 hour' |
interval '03:30:00' |
/ |
interval '1 hour' / double precision '1.5' |
interval '00:40:00' |
表 9.28. 日期/时间函数
| Function | Return Type | 描述 | 示例 | Result |
|---|---|---|---|---|
|
interval |
Subtract arguments, producing a “symbolic” result that uses years and months | age(timestamp '2001-04-10', timestamp '1957-06-13') |
43 years 9 mons 27 days |
|
interval |
从 current_date(午夜)减去 |
age(timestamp '1957-06-13') |
43 years 8 mons 3 days |
|
timestamp with time zone |
Current date and time (changes during statement execution); see 第 9.9.4 节 | ||
|
date |
Current date; see 第 9.9.4 节 | ||
|
time with time zone |
Current time of day; see 第 9.9.4 节 | ||
|
timestamp with time zone |
Current date and time (start of current transaction); see 第 9.9.4 节 | ||
|
double precision |
获取子字段(等价于 extract);参见第 9.9.1 节 |
date_part('hour', timestamp '2001-02-16 20:38:40') |
20 |
|
double precision |
获取子字段(等价于 extract);参见第 9.9.1 节 |
date_part('month', interval '2 years 3 months') |
3 |
|
timestamp |
截断到指定精度;另见第 9.9.2 节 | date_trunc('hour', timestamp '2001-02-16 20:38:40') |
2001-02-16 20:00:00 |
|
double precision |
获取子字段;参见第 9.9.1 节 | extract(hour from timestamp '2001-02-16 20:38:40') |
20 |
|
double precision |
获取子字段;参见第 9.9.1 节 | extract(month from interval '2 years 3 months') |
3 |
|
boolean |
测试时间戳是否有限(不是正负无穷) | isfinite(date '2001-02-16') |
true |
|
boolean |
测试时间戳是否有限(不是正负无穷) | isfinite(timestamp '2001-02-16 21:28:30') |
true |
|
boolean |
测试时间戳是否有限(不是正负无穷) | isfinite(interval '4 hours') |
true |
|
interval |
调整 interval,把 30 天的时间段表示为月 | justify_days(interval '35 days') |
1 mon 5 days |
|
interval |
调整 interval,把 24 小时的时间段表示为天 | justify_hours(interval '27 hours') |
1 day 03:00:00 |
|
interval |
使用justify_days和justify_hours调整 interval,并附加符号调整 |
justify_interval(interval '1 mon -1 hour') |
29 days 23:00:00 |
|
time |
Current time of day; see 第 9.9.4 节 | ||
|
timestamp |
Current date and time (start of current transaction); see 第 9.9.4 节 | ||
|
timestamp with time zone |
Current date and time (start of current transaction); see 第 9.9.4 节 | ||
|
timestamp with time zone |
Current date and time (start of current statement); see 第 9.9.4 节 | ||
|
text |
Current date and time (like clock_timestamp, but as a text string); see 第 9.9.4 节 |
||
|
timestamp with time zone |
Current date and time (start of current transaction); see 第 9.9.4 节 |
除了这些函数以外,还支持 SQL 操作符OVERLAPS:
(start1,end1) OVERLAPS (start2,end2) (start1,length1) OVERLAPS (start2,length2)
当两个时间段(由其端点定义)重叠时,该表达式产生真;不重叠时产生假。端点可以指定为一对日期、时间或时间戳;也可以是一个日期、时间或时间戳后跟一个 interval。当提供一对值时,可以先写开始也可以先写结束;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 with time zone值上(或从中减去一个interval值)时,天数部分会按指定的天数推进或退回timestamp with time zone的日期。当跨越夏令时变化时(会话时区设置为识别夏令时的时区),这意味着interval '1 day'不一定等于interval '24 hours'。例如,将会话时区设置为CST7CDT时, timestamp with time zone '2005-04-02 12:00-07' + interval '1 day' will produce timestamp with time zone '2005-04-03 12:00-06', 而把interval '24 hours'加到同一个初始timestamp with time zone上会产生timestamp with time zone '2005-04-03 13:00-06',因为在时区CST7CDT中,2005-04-03 02: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, date_part #EXTRACT(fieldFROMsource)
extract函数从日期/时间值中提取年份、小时等子字段。source必须是timestamp、time或interval类型的值表达式。(date类型的表达式会转换为timestamp,因此也可以使用。)field是一个标识符或字符串,用于选择从源值中提取的字段。extract函数返回的值的类型为double precision。以下是有效的字段名称:
century世纪
SELECT EXTRACT(CENTURY FROM TIMESTAMP '2000-12-16 12:21:13'); Result:20SELECT EXTRACT(CENTURY FROM TIMESTAMP '2001-02-16 20:38:40'); Result:21
第一个世纪从公元 0001-01-01 00:00:00 开始,尽管当时的人并不知道这一点。这个定义适用于所有使用格里高利历的国家。没有世纪编号 0,你从 -1 世纪直接到 1 世纪。 如果对此有异议,请把你的意见寄到:罗马,圣彼得大教堂,教皇收。
PostgreSQL 8.0 之前的版本不遵循通常的世纪编号,而只是返回年份数字除以 100 的结果。
day(月中的)日字段(1 - 31)
SELECT EXTRACT(DAY FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 16
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
epochFor date and timestamp values, the number of seconds since 1970-01-01 00:00:00 UTC (can be negative); 对interval值,是该 interval 中的总秒数
SELECT EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40.12-08'); Result:982384720.12SELECT EXTRACT(EPOCH FROM INTERVAL '5 days 3 hours'); Result:442800
下面说明如何把 epoch 值转换回时间 stamp:
SELECT TIMESTAMP WITH TIME ZONE 'epoch' + 982384720.12 * INTERVAL '1 second';
(to_timestamp函数封装了上述转换。)
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 星期编号年 falls in (not applicable to intervals)
SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-01'); Result:2005SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-02'); Result:2006
每个ISO 8601 星期编号年都从包含 1 月 4 日的那个星期的星期一开始,因此在 1 月上旬或 12 月下旬,ISO年可能与格里高利年不同。更多信息见week字段。
该字段在 PostgreSQL 8.3 之前的版本中不可用。
microseconds秒字段(包含小数部分)乘以 1 000 000;注意这包含完整的秒
SELECT EXTRACT(MICROSECONDS FROM TIME '17:12:28.5');
Result: 28500000
millenniumThe millennium
SELECT EXTRACT(MILLENNIUM FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 3
1900 年代属于第二个千年。第三个千年始于 2001 年 1 月 1 日。
PostgreSQL 8.0 之前的版本不遵循通常的千年编号,而只是返回年份数字除以 1000 的结果。
millisecondsThe seconds field, including fractional parts, multiplied by 1000。注意这包含完整的秒。
SELECT EXTRACT(MILLISECONDS FROM TIME '17:12:28.5');
Result: 28500
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:2SELECT EXTRACT(MONTH FROM INTERVAL '2 years 3 months'); Result:3SELECT 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秒字段(包含小数部分)(0 - 59[6])
SELECT EXTRACT(SECOND FROM TIMESTAMP '2001-02-16 20:38:40'); Result:40SELECT EXTRACT(SECOND FROM TIME '17:12:28.5'); Result:28.5
timezone相对 UTC 的时区偏移,以秒计。正值对应 UTC 以东的时区,负值对应 UTC 以西的时区。
timezone_hour时区偏移的小时部分
timezone_minute时区偏移的分钟部分
week一年中ISO 8601 星期编号的周号。按照定义,ISO 周从星期一开始,且一年的第 1 周包含该年的 1 月 4 日。换句话说,一年的第一个星期四属于该年的第 1 周。
在 ISO 星期编号系统中,1 月上旬的日期可能属于上一年的第 52 或 53 周,而 12 月下旬的日期可能属于下一年的第 1 周。例如,2005-01-01属于 2004 年的第 53 周,2006-01-01属于 2005 年的第 52 周,而2012-12-31属于 2013 年的第 1 周。建议把isoyear字段与week一起使用以获得一致的结果。
SELECT EXTRACT(WEEK FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 7
year年份字段。请记住没有公元 0 年,因此从公元(AD)年份减去公元前(BC)年份时应小心。
SELECT EXTRACT(YEAR FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 2001
extract函数主要的用途是做计算性处理。对于用于显示的日期/时间值格式化,参阅第 9.8 节。
date_part函数仿照传统的Ingres实现,后者对应SQL标准的extract函数:
date_part('field', source)
注意,此处的field参数必须是字符串值,而不能是名称。date_part的有效字段名与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)
source是timestamp或interval类型的值表达式。(类型为date和time的值会自动转换为timestamp或interval,分别对应这两种输入类型。)field选择输入值的截断精度。返回值的类型是timestamp或interval,所有小于所选精度的字段都设为零(日和月则设为一)。
field的有效值是:
microseconds |
milliseconds |
second |
minute |
hour |
day |
week |
month |
quarter |
year |
decade |
century |
millennium |
示例:
SELECT date_trunc('hour', TIMESTAMP '2001-02-16 20:38:40');
结果:2001-02-16 20:00:00
SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40');
结果:2001-01-01 00:00:00
AT TIME ZONE #AT TIME ZONE结构允许把时间戳转换到不同的时区。表 9.29展示了它的各种变体。
表 9.29. AT TIME ZONE 变体
| Expression | Return Type | 描述 |
|---|---|---|
|
timestamp with time zone |
将给定的不带时区时间戳视为指定时区中的时间 |
|
timestamp without time zone |
将给定的带时区时间戳转换为新时区的时间,结果不带时区标识 |
|
time with time zone |
将给定的带时区时间转换为新时区的时间 |
在这些表达式里,所需的时区zone可以指定为文本字符串(例如'PST'),也可以指定为一个间隔(例如INTERVAL '-08:00')。在文本情况下,时区名称可以按第 8.5.3 节中描述的任意方式指定。
示例(假定本地时区为PST8PDT):
SELECT TIMESTAMP '2001-02-16 20:38:40' AT TIME ZONE 'MST'; 结果:2001-02-16 19:38:40-08SELECT TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-05' AT TIME ZONE 'MST'; 结果:2001-02-16 18:38:40
第一个示例取一个不带时区的时间戳,把它解释为 MST 时间(UTC-7),然后转换成 PST(UTC-8)显示。第二个示例取一个以 EST(UTC-5)指定的时间戳,把它转换成 MST(UTC-7)的本地时间。
函数等效于符合 SQL 标准的结构timezone(zone, timestamp)。timestamp AT TIME ZONE zone
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; 结果:14:39:53.662522-05SELECT CURRENT_DATE; 结果:2001-12-23SELECT CURRENT_TIMESTAMP; 结果:2001-12-23 14:39:53.662522-05SELECT CURRENT_TIMESTAMP(2); 结果:2001-12-23 14:39:53.66-05SELECT LOCALTIMESTAMP; 结果:2001-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'; -- incorrect for use with DEFAULT
在创建表时指定DEFAULT子句的情况下,你不希望使用第三种形式。 系统将在分析这个常量的时候把now转换为一个timestamp, 这样需要默认值时就会得到创建表的时间!而前两种形式要到实际使用默认值的时候才被计算, 因为它们是函数调用。因此它们可以给出每次插入行的时刻。
以下函数可用于延迟服务器进程的执行:
pg_sleep(seconds)
pg_sleep使当前会话的进程休眠seconds秒。seconds的类型为double precision,因此可以指定带小数部分的秒数作为延迟时间。例如:
SELECT pg_sleep(1.5);
有效的休眠时间间隔精度是平台相关的,通常 0.01 秒是通用值。休眠延迟将至少持续指定的时长,也有可能由于服务器负荷等因素而比指定的时间长。
请确保在调用pg_sleep时,你的会话没有持有不必要的锁。否则其它会话可能必须等待你的休眠会话,因而减慢整个系统速度。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。