Table 9-26 显示了 PostgreSQL 里可以用于处理日期/时间数值的函数,随后一节里描述了细节。 Table 9-25 演示了基本算术操作符 (+,* 等等)的行为。 而与格式化相关的函数,可以参考Section 9.8。 你应该很熟悉来自 Section 8.5 的日期/时间数据类型的背景知识。
所有下面描述的函数和操作符接收的time或者timestamp输入实际上都来自两种可能: 一个是接收time with time zone 或 timestamp with time zone, 另外一种是time without time zone 或者 timestamp without time zone。 出于简化考虑,这些变种没有独立显示出来。还有,+ 和 * 操作符都是以可交换的操作符对方式存在的 (比如,date + integer 和 integer + date);我们只显示了这样的交换操作符对中的一个。
Table 9-25. 日期/时间操做符
操作符 | 例子 | 结果 |
---|---|---|
+ | date '2001-09-28' + integer '7' | date '2001-10-05' |
+ | date '2001-09-28' + interval '1 hour' | timestamp '2001-09-28 01:00' |
+ | date '2001-09-28' + time '03:00' | timestamp '2001-09-28 03:00' |
+ | interval '1 day' + interval '1 hour' | interval '1 day 01:00' |
+ | timestamp '2001-09-28 01:00' + interval '23 hours' | timestamp '2001-09-29 00:00' |
+ | time '01:00' + interval '3 hours' | time '04:00' |
- | - interval '23 hours' | interval '-23:00' |
- | date '2001-10-01' - date '2001-09-28' | integer '3' |
- | date '2001-10-01' - integer '7' | date '2001-09-24' |
- | date '2001-09-28' - interval '1 hour' | timestamp '2001-09-27 23:00' |
- | time '05:00' - time '03:00' | interval '02:00' |
- | time '05:00' - interval '2 hours' | time '03:00' |
- | timestamp '2001-09-28 23:00' - interval '23 hours' | timestamp '2001-09-28 00:00' |
- | interval '1 day' - interval '1 hour' | interval '23:00' |
- | timestamp '2001-09-29 03:00' - timestamp '2001-09-27 12:00' | interval '1 day 15:00' |
* | interval '1 hour' * double precision '3.5' | interval '03:30' |
/ | interval '1 hour' / double precision '1.5' | interval '00:40' |
Table 9-26. 日期/时间函数
函数 | 返回类型 | 描述 | 例子 | 结果 |
---|---|---|---|---|
age (timestamp, timestamp) | interval | 减去参数,生成一个使用年、月的"符号化"的结果 | age('2001-04-10', timestamp '1957-06-13') | 43 years 9 mons 27 days |
age (timestamp) | interval | 从current_date 减去得到的数值 | age(timestamp '1957-06-13') | 43 years 8 mons 3 days |
current_date | date | 今天的日期;见 Section 9.9.4 | ||
current_time | time with time zone | 现在的时间;见 Section 9.9.4 | ||
current_timestamp | timestamp with time zone | 日期和时间;见 Section 9.9.4 | ||
date_part (text, timestamp) | double precision | 获取子域(等效于
extract );又见 Section 9.9.1
| date_part('hour', timestamp '2001-02-16 20:38:40') | 20 |
date_part (text, interval) | double precision | 获取子域(等效于
extract );又见 Section 9.9.1
| date_part('month', interval '2 years 3 months') | 3 |
date_trunc (text, timestamp) | timestamp | 截断成指定的精度;又见Section 9.9.2 | date_trunc('hour', timestamp '2001-02-16 20:38:40') | 2001-02-16 20:00:00+00 |
extract (field from timestamp) | double precision | 获取子域;又见 Section 9.9.1 | extract(hour from timestamp '2001-02-16 20:38:40') | 20 |
extract (field from interval) | double precision | 获取子域;又见 Section 9.9.1 | extract(month from interval '2 years 3 months') | 3 |
isfinite (timestamp) | boolean | 测试有穷时间戳(非无穷) | isfinite(timestamp '2001-02-16 21:28:30') | true |
isfinite (interval) | boolean | 测试有穷时间间隔 | isfinite(interval '4 hours') | true |
localtime | time | 今日的时间;见 Section 9.9.4 | ||
localtimestamp | timestamp | 日期和时间;见 Section 9.9.4 | ||
now () | timestamp with time zone | 当前的日期和时间(等效于
current_timestamp );见Section 9.9.4
| ||
timeofday () | text | 当前日期和时间;见Section 9.9.4 |
If you are using both justify_hours
and justify_days
,
it is best to use justify_hours
first so any additional days will
justified by justify_days
.
如果你同时使用 justify_hours
和 justify_days
,
那么最好先用 justify_hours
,这样任何额外的天数都会被 justify_days
对齐。
除了这些函数以外,还支持 SQL 操作符 OVERLAPS:
(start1, end1 ) OVERLAPS ( start2, end2) (start1, length1 ) OVERLAPS ( start2, length2)
这个表达式在两个时间域(用它们的终点定义)重叠的时候生成真值。 终点可以以一对日期,时间,或者时间戳来声明;或者是一个后面跟着一个时间间隔的 日期,时间,时间戳。
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
EXTRACT
,date_part
EXTRACT(field from source)
extract
函数从日期/时间数值里抽取
子域,比如年或者小时等。source
必须是一个类型 timestamp,time,或者 interval 的值表达式。
(类型为 date 的表达式将转换为 timestamp,因此也可以用。)
field 是一个标识符
或者字串,它指定从源数据中抽取的数域。extract
函数返回类型为double precision 的数值。
下列数值是有效数据域的名字∶
世纪。
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 AD 开始, 尽管那时候人们还不知道这是第一个世纪。这个定义适用于所有使用格里高利历法的国家。 没有 0 世纪,我们直接从公元前 1 世纪到公元 1 世纪。 如果你认为这个不合理,那么请把抱怨发给:罗马圣彼得教堂,梵蒂冈,教皇收。
PostgreSQL 8.0 以前版本里并不遵循世纪的习惯编号,只是把年份除以 100。
(月分)里的日期域(1-31)
SELECT EXTRACT(DAY from TIMESTAMP '2001-02-16 20:38:40'); Result: 16
年份域除以10
SELECT EXTRACT(DECADE from TIMESTAMP '2001-02-16 20:38:40'); Result: 200
每周的星期号(0 - 6;星期天是 0) (仅用于 timestamp)
SELECT EXTRACT(DOW FROM TIMESTAMP '2001-02-16 20:38:40'); Result: 5
请注意 extract
的星期几编号和 to_char
函数的不同。
一年的第几天(1 -365/366) (仅用于 timestamp)
SELECT EXTRACT(DOY from TIMESTAMP '2001-02-16 20:38:40'); Result: 47
对于 date 和 timestamp 数值而言, 是自 1970-01-01 00:00:00 以来的秒数(结果可能是负数。); 对于 interval 数值而言,它是时间间隔的总秒数。
SELECT EXTRACT(EPOCH from TIMESTAMP '2001-02-16 20:38:40'); Result: 982352320 SELECT EXTRACT(EPOCH from INTERVAL '5 days 3 hours'); Result: 442800
下面是把 epoch 值转换回时间戳的方法:
SELECT TIMESTAMP WITH TIME ZONE 'epoch' + 982384720 * INTERVAL '1 second';
小时域 (0 - 23)
SELECT EXTRACT(HOUR from TIMESTAMP '2001-02-16 20:38:40'); Result: 20
秒域,包括小数部分,乘以 1,000,000。请注意它包括全部的秒。
SELECT EXTRACT(MICROSECONDS from TIME '17:12:28.5'); Result: 28500000
千年。
SELECT EXTRACT(MILLENNIUM from TIMESTAMP '2001-02-16 20:38:40'); Result: 3
20世纪(19xx年)里面的年份在第二个千年里。第三个千年从 2001 年一月一日开始。
PostgreSQL 8.0 之前的版本并不遵循前年编号的习惯,只是返回年份除以 1000。
秒域,包括小数部分,乘以 1000。请注意它包括完整的秒。
SELECT EXTRACT(MILLISECONDS from TIME '17:12:28.5'); Result: 28500
分钟域 (0 - 59)
SELECT EXTRACT(MINUTE from TIMESTAMP '2001-02-16 20:38:40'); Result: 38
对于 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
该天所在的该年的季度(1 - 4)(仅用于 timestamp)
SELECT EXTRACT(QUARTER from TIMESTAMP '2001-02-16 20:38:40'); Result: 1
秒域,包括小数部分 (0 - 59 [1])
SELECT EXTRACT(SECOND from TIMESTAMP '2001-02-16 20:38:40'); Result: 40 SELECT EXTRACT(SECOND from TIME '17:12:28.5'); Result: 28.5
与 UTC 的时区偏移,以秒记。正数对应 UTC 东边的时区,负数对应 UTC 西边的时区。
时区偏移的小时部分。
时区偏移的分钟部分。
该天在所在的年份里是第几周。根据定义 (ISO 8601), 一年的第一周包含该年的一月四日。(ISO-8601的周从星期一开始。) 换句话说,一年的第一个星期四在第一周。(只用于 timestamp 数值)。
因此,一月的头几天可能是前一年的第五十二或者第五十三周。比如, 2005-01-01 是 2004 年的第五十三周,而 2006-01-01 是 2005 年的第五十二周。
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
extract
函数主要的用途是做运算用。
对于用于显示的日期/时间数值格式化,参阅
Section 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 的值表达式(类型 date 和 time 的数值都分别自动转换成timestamp或者interval)。 用 field 选择对该时间戳数值 选用什么样的精度进行截断)。 返回的数值是 timestamp 类型或者interval,所有小于选定的 精度的域都设置为零(或者一,如果是日期和月份域的话)。
field 的有效数值是∶
microseconds |
milliseconds |
second |
minute |
hour |
day |
week |
month |
year |
decade |
century |
millennium |
例子:
SELECT date_trunc('hour', TIMESTAMP '2001-02-16 20:38:40'); Result: 2001-02-16 20:00:00+00 SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40'); Result: 2001-01-01 00:00:00+00
AT TIME ZONE 构造允许把时间戳转换成不同的 时区。Table 9-27 显示了其变体。
Table 9-27. AT TIME ZONE变体
表达式 | 返回类型 | 描述 |
---|---|---|
timestamp without time zone AT TIME ZONE zone | timestamp with time zone | 把给出的不带时区的时间戳转换成指定时区的时间 |
timestamp with time zone AT TIME ZONE zone | timestamp without time zone | 把给出的带时区的时间转换为转换成给定时区的时间 |
time with time zone AT TIME ZONE zone | time with time zone | 在时区之间转换当地时间 |
在这些表达式里,我们需要的 zone 可以声明为 文本串(比如,'PST')或者一个时间间隔 (比如,INTERVAL '-08:00')。 在文本的情况下,可用的时区名字要么在 Table B-4 要么在 Table B-4 里面。
例子(假设本地时区是 PST8PDT):
SELECT TIMESTAMP '2001-02-16 20:38:40' AT TIME ZONE 'MST'; Result: 2001-02-16 19:38:40-08 SELECT TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-05' AT TIME ZONE 'MST'; Result: 2001-02-16 18:38:40
第一个例子接受一个无时区的时间戳然后把她解释成 MST 时间(UTC-7) 生成 UTC 时间戳,然后这个时间转换为 PST(UTC-8)来显示。 第二个例子接受一个声明为 EST(UTC-5)的时间戳,然后把它 转换成 MST(UTC-7)的当地时间。
函数timezone
(zone, timestamp)
等效于 SQL 兼容的构造timestamp AT TIME ZONE zone。
我们可以使用下面的函数获取当前的日期和/或时间∶
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
可以有选择地给予一个精度参数,
该精度导致结果的秒数域园整为指定小数位。如果没有精度参数,
将给予所能得到的全部精度。
注意: 在 PostgreSQL 7.2 之前没有实现精度参数, 结果总是给出整数的秒。
一些例子:
SELECT CURRENT_TIME; Result: 14:39:53.662522-05 SELECT CURRENT_DATE; Result: 2001-12-23 SELECT CURRENT_TIMESTAMP; Result: 2001-12-23 14:39:53.662522-05 SELECT CURRENT_TIMESTAMP(2); Result: 2001-12-23 14:39:53.66-05 SELECT LOCALTIMESTAMP; Result: 2001-12-23 14:39:53.662522
函数 now()
是传统的
PostgreSQL 和
CURRENT_TIMESTAMP
的等效物。
还有一件事提醒大家,那就是 CURRENT_TIMESTAMP
和相关的函数把时间当做当前事务的开始返回;在事务运行的时候,
它们的数值并不改变。
我们认为这是一个特性:目的是为了允许一个事务在"当前"
时间上有连贯的概念,这样在同一个事务离得多个修改可以有同样的时间戳。
注意: 许多其它数据库系统更频繁地更新这些数值。
还有一个 timeofday()
函数,它返回实时的时间值,
并且会在事务里随时间前进。
由于历史原因,它返回一个text字串,而不是 timestamp 值∶
SELECT timeofday(); Result: Sat Feb 17 19:07:32.000126 2001 EST
所有日期/时间类型还接受特殊的文本值 now, 用于声明当前的日期和时间。因此,下面三个都返回相同的结果∶
SELECT CURRENT_TIMESTAMP; SELECT now(); SELECT TIMESTAMP 'now'; -- 用在 DEFAULT 里是不正确的
提示: 在创建表声明一个DEFAULT值的时候你是不会想用第三种形式的。 因为系统将在分析这个常量的时候把 now 转换成 一个 timestamp,因此在需要缺省值的时候, 就会使用创建表的时间! 而头两种形式要到实际使用缺省值的时候才计算, 因为它们是函数调用。因此它们可以给出插入时间行的时候 需要的缺省行为。
[1] | 如果操作系统实现了润秒, 那么上限是 60 |