PostgreSQL 8.2.3 中文文檔
後退快退章9. 函數和操作符快進前進

9.9. 時間/日期函數和操作符

表9-26顯示了 PostgreSQL 裡可以用於處理日期/時間數值的函數,隨後一節裡描述了細節。表9-25演示了基本算術操作符的行為。而與格式化相關的函數,可以參考節9.8。你應該很熟悉節8.5的日期/時間數據類型的背景知識。

所有下述函數和操作符接收的 timetimestamp 輸入實際上都來自兩種可能:一種是接收 time with time zonetimestamp with time zone ,另外一種是接收 time without time zonetimestamp 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)intervalcurrent_date 減去參數後的結果age(timestamp '1957-06-13')43 years 8 mons 3 days
clock_timestamp()timestamp with time zone實時時鐘的當前時間戳;見節9.9.4  
current_datedate當前的日期;見節9.9.4  
current_timetime with time zone當日時間;見節9.9.4  
current_timestamptimestamp with time zone當前事務開始時的時間戳;見節9.9.4  
date_part(text, timestamp)double precision獲取子域(等效於 extract);又見節9.9.1date_part('hour', timestamp '2001-02-16 20:38:40')20
date_part(text, interval)double precision獲取子域(等效於 extract);又見節9.9.1date_part('month', interval '2 years 3 months')3
date_trunc(text, timestamp)timestamp截斷成指定的精度;又見節9.9.2date_trunc('hour', timestamp '2001-02-16 20:38:40')2001-02-16 20:00:00
extract(field from timestamp)double precision獲取子域;又見節9.9.1extract(hour from timestamp '2001-02-16 20:38:40')20
extract(field from interval)double precision獲取子域;又見節9.9.1extract(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_daysjustify_hours 調整時間間隔的同時進行正負號調整justify_interval(interval '1 mon -1 hour')29 days 23:00:00
localtimetime當日時間;見節9.9.4  
localtimestamptimestamp當前事務開始時的時間戳;見節9.9.4  
now()timestamp with time zone當前事務開始時的時間戳;見節9.9.4  
statement_timestamp()timestamp with time zone實時時鐘的當前時間戳;見節9.9.4  
timeofday()textclock_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 的時候有一個夏令時變更。

9.9.1. EXTRACT, date_part

EXTRACT(field FROM source)

extract 函數從日期/時間數值裡抽取子域,比如年、小時等。source 必須是一個 timestamp, time, interval 類型的值表達式(類型為 date 的表達式將轉換為 timestamp ,因此也可以用)。field 是一個標識符或者字符串,它指定從源數據中抽取的域。extract 函數返回類型為 double precision 的數值。下列數值是有效數據域的名字:

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 AD 開始,儘管那時候人們還不知道這是第一個世紀。這個定義適用於所有使用陽曆的國家。冇有 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 ;星期天是 0)(僅用於 timestamp 值)

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

請注意,extract 的星期幾編號和 to_char 函數不同。

doy

一年的第幾天(1-365/366)(僅用於 timestamp 值)

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

對於 datetimestamp 值而言,是自 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';
hour

小時域(0-23)

SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 20
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

20 世紀(19xx 年)裡麵的年份在第二個千年裡。第三個千年從 2001 年 1 月 1 日零時開始。

PostgreSQL 8.0 之前的版本並不遵循前年編號的習慣,隻是返回年份除以 1000 。

milliseconds

秒域(包括小數部分)乘以 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: 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)(僅用於 timestamp 值)

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

秒域,包括小數部分(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
timezone

與 UTC 的時區偏移量,以秒記。正數對應 UTC 東邊的時區,負數對應 UTC 西邊的時區。

timezone_hour

時區偏移量的小時部分。

timezone_minute

時區偏移量的分鐘部分。

week

該天在所在的年份裡是第幾周。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
year

年份域。要記住這裡冇有 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

9.9.2. date_trunc

date_trunc 函數在概念上和用於數字的 trunc 函數類似。

date_trunc('field', source)

sourcetimestampinterval 類型的值表達式(datetime 類型的值都分彆自動轉換成 timestampinterval)。用 field 選擇對該時間戳值用什麼樣的精度進行截斷。返回的數值是 timestampinterval 類型,所有小於選定的精度的域都設置為零(日期和月份域則為 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

9.9.3. AT TIME ZONE

AT TIME ZONE 構造允許把時間戳轉換成不同的時區。表9-27顯示了其變體。

表9-27. AT TIME ZONE 變體

表達式返回類型描述
timestamp without time zone AT TIME ZONE zonetimestamp with time zone把給出的不帶時區的時間戳轉換成給定時區的時間戳
timestamp with time zone AT TIME ZONE zonetimestamp without time zone把給出的帶時區的時間戳轉換成給定時區的時間戳
time with time zone AT TIME ZONE zonetime 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

9.9.4. 當前日期/時間

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_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 ,因此這個缺省值就會變成創建表的時間!而前兩種形式要到實際使用缺省值的時候才計算,因為它們是函數調用。因此它們可以給出每次插入行的時刻。

9.9.5. 延時執行

下麵的這個函數可以用於讓服務器進程延時執行:

pg_sleep(seconds)

pg_sleep 讓當前的會話進程休眠 seconds 秒以後再執行。seconds 是一個 double precision 類型的值,所以可以指定帶小數的秒數。例如:

SELECT pg_sleep(1.5);

【注意】有效的休眠時間間隔精度是平台相關的,通常 0.01 秒是通用的。休眠的時間將至少等於指定的時間,也有可能由於服務器荷載較重等原因而比指定的時間長。

警告

請確保調用 pg_sleep 的會話冇有持有不必要的鎖。否則其它會話可能必須等待這個休眠的會話釋放所持有的鎖,從而減慢係統速度。

注意

[1]

如果操作係統實現了潤秒,那麼上限是 60 。


後退首頁前進
數據類型格式化函數上一級幾何函數和操作符