表9-26顯示了 PostgreSQL 裡可以用於處理日期/時間數值的函數,隨後一節裡描述了細節。表9-25演示了基本算術操作符的行為。而與格式化相關的函數,可以參考節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-25. 日期/時間操做符
操作符 | 例子 | 結果 |
---|---|---|
+ | 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' |
- | 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-26. 日期/時間函數
函數 | 返回類型 | 描述 | 例子 | 結果 |
---|---|---|---|---|
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') | 43 years 8 mons 3 days |
clock_timestamp () | timestamp with time zone | 實時時鐘的當前時間戳;見節9.9.4 | ||
current_date | date | 當前的日期;見節9.9.4 | ||
current_time | time with time zone | 當日時間;見節9.9.4 | ||
current_timestamp | timestamp with time zone | 當前事務開始時的時間戳;見節9.9.4 | ||
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_trunc (text, timestamp) | timestamp | 截斷成指定的精度;又見節9.9.2 | date_trunc('hour', timestamp '2001-02-16 20:38:40') | 2001-02-16 20:00:00 |
extract (field from timestamp) | double precision | 獲取子域;又見節9.9.1 | extract(hour from timestamp '2001-02-16 20:38:40') | 20 |
extract (field from interval) | double precision | 獲取子域;又見節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 |
justify_days (interval) | interval | 按照每月 30 天調整時間間隔 | justify_days(interval '30 days') | 1 month |
justify_hours (interval) | interval | 按照每天 24 小時調整時間間隔 | justify_hours(interval '24 hours') | 1 day |
justify_interval (interval) | interval | 使用 justify_days 和 justify_hours 調整時間間隔的同時進行正負號調整 | justify_interval(interval '1 mon -1 hour') | 29 days 23:00:00 |
localtime | time | 當日時間;見節9.9.4 | ||
localtimestamp | timestamp | 當前事務開始時的時間戳;見節9.9.4 | ||
now () | timestamp with time zone | 當前事務開始時的時間戳;見節9.9.4 | ||
statement_timestamp () | timestamp with time zone | 實時時鐘的當前時間戳;見節9.9.4 | ||
timeofday () | text | 與 clock_timestamp 相同,但結果是一個 text 字符串;見節9.9.4 | ||
transaction_timestamp () | timestamp with time zone | 當前事務開始時的時間戳;見節9.9.4 |
除了這些函數以外,還支持 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
當把 interval 值添加到 timestamp with time zone 上(或從中減去)的時候,days 部分會按照指定的天數增加(或減少) timestamp with time zone 的日期。對於橫跨夏令時的變化(會話的時區設置被識彆為夏時製),interval '1 day' 並不一定等於 interval '24 hours' 。例如,當會話的時區設置為 CST7CDT 的時候,timestamp with time zone '2005-04-02 12:00-07' + interval '1 day' 的結果是 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 的時候有一個夏令時變更。
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-00 以來的秒數(結果可能是負數);對於 interval 值而言,它是時間間隔的總秒數。
SELECT EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-08'); Result: 982384720 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 年 1 月 1 日零時開始。
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 值)
因此,一月的頭幾天可能是前一年的第 52 或者第 53 周。比如,2005-01-01 是 2004 年的第 53 周,而 2006-01-01 是 2005 年的第 52 周。
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
函數主要的用途是運算。對於用於顯示的日期/時間數值格式化,參閱節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 類型,所有小於選定的精度的域都設置為零(日期和月份域則為 1)。
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'); 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
AT TIME ZONE 構造允許把時間戳轉換成不同的時區。表9-27顯示了其變體。
表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')。在文本的情況下,可用的時區名字在節8.5.3有詳細描述。
例子(假設本地時區是 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
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; 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
因為這些函數全部都按照當前事務的開始時刻返回結果,所以它們的值在事務運行的整個期間內都不改變。我們認為這是一個特性:目的是為了允許一個事務在"當前時間"上有連貫的概念,這樣在同一個事務裡的多個修改可以保持同樣的時間戳。
【注意】許多其它數據庫係統更頻繁地更新這些數值。
PostgreSQL 同樣也提供了返回實時時間值的函數,它們的返回值會在事務中隨時間的前進而變化。這些不附合 SQL 標準的函數列表如下:
now() transaction_timestamp() statement_timestamp() clock_timestamp() timeofday()
now()
是傳統的 PostgreSQL 和 CURRENT_TIMESTAMP
等效的函數。transaction_timestamp()
等效於 CURRENT_TIMESTAMP
,不過其命名準確的表明了其含義。statement_timestamp()
返回當前事務開始時刻的時間戳(更準確的說是收到客戶端最後一條命令的時間)。statement_timestamp()
和 transaction_timestamp()
在一個事務的第一條命令裡返回值相同,但是在隨後的命令中卻不一定相同。clock_timestamp()
返回實時時鐘的當前時間戳,因此它的值甚至在同一條 SQL 命令中都會變化。timeofday()
相當於 clock_timestamp()
,也返回實時時鐘的當前時間戳,由於曆史原因,它返回一個 text 字符串,而不是 timestamp with time zone 值。
所有日期/時間類型還接受特殊的文本值 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 秒是通用的。休眠的時間將至少等於指定的時間,也有可能由於服務器荷載較重等原因而比指定的時間長。
警告 |
請確保調用 |
[1] | 如果操作係統實現了潤秒,那麼上限是 60 。 |