支援的版本: 目前 (17) / 16 / 15 / 14 / 13
開發版本: devel
不再支援的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

9.9. 日期/時間函數和運算符 #

表 9.33 顯示了可用於日期/時間值處理的函數,詳細資訊請參閱以下小節。表 9.32 說明了基本算術運算符(+* 等)的行為。關於格式化函數,請參閱第 9.8 節。您應該熟悉來自第 8.5 節關於日期/時間資料類型的背景資訊。

此外,表 9.1 中顯示的常用比較運算符可用於日期/時間類型。日期和時間戳(帶或不帶時區)都是可比較的,而時間(帶或不帶時區)和時間間隔只能與相同資料類型的值進行比較。當比較沒有時區的時間戳和有時區的時間戳時,前者值將被假定為由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

從時間中減去一個時間間隔

time '05:00' - interval '2 hours'03:00:00

timestamp - intervaltimestamp

從時間戳記中減去一個時間間隔

timestamp '2001-09-28 23:00' - interval '23 hours'2001-09-28 00:00:00

interval - intervalinterval

時間間隔相減

interval '1 day' - interval '1 hour'1 day -01:00:00

timestamp - timestampinterval

時間戳記相減(將 24 小時間隔轉換為天,類似於 justify_hours()

timestamp '2001-09-29 03:00' - timestamp '2001-07-27 12:00'63 days 15:00:00

interval * double precisioninterval

將時間間隔乘以純量

interval '1 second' * 90000:15:00

interval '1 day' * 2121 days

interval '1 hour' * 3.503:30:00

interval / double precisioninterval

將時間間隔除以純量

interval '1 hour' / 1.500:40:00


表格 9.33。日期/時間函數

函數

描述

範例

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')62 years 6 mons 10 days

clock_timestamp ( ) → timestamp with time zone

目前日期和時間 (在語句執行期間會變更);請參閱第 9.9.5 節

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

current_datedate

目前日期;請參閱第 9.9.5 節

current_date2019-12-23

current_timetime with time zone

目前時間;請參閱第 9.9.5 節

current_time14:39:53.662522-05

current_time ( integer ) → time with time zone

目前時間,具有有限的精確度;請參閱第 9.9.5 節

current_time(2)14:39:53.66-05

current_timestamptimestamp with time zone

目前日期和時間 (目前交易的開始時間);請參閱第 9.9.5 節

current_timestamp2019-12-23 14:39:53.662522-05

current_timestamp ( integer ) → timestamp with time zone

目前日期和時間 (目前交易的開始時間),具有有限的精確度;請參閱第 9.9.5 節

current_timestamp(0)2019-12-23 14:39:53-05

date_add ( timestamp with time zone, interval [, text ] ) → timestamp with time zone

interval 加到 timestamp with time zone,根據第三個參數指定的時區或目前的TimeZone設定(如果省略),計算一天中的時間和日光節約時間調整。 具有兩個參數的形式相當於 timestamp with time zone + 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 '1 year 65 days')1 year 2 mons 5 days

justify_hours ( interval ) → interval

調整間隔,將 24 小時的時間段轉換為天數

justify_hours(interval '50 hours 10 minutes')2 days 02:10: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

從年、月、日、時、分和秒欄位建立含時區的時間戳記(負數年份表示西元前)。如果未指定 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 with time zone

目前日期和時間 (目前交易的開始時間);請參閱第 9.9.5 節

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

statement_timestamp ( ) → timestamp with time zone

目前日期與時間(目前陳述式的開始);請參閱第 9.9.5 節

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

timeofday ( ) → text

目前日期與時間(如同 clock_timestamp,但以 text 字串表示);請參閱第 9.9.5 節

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

transaction_timestamp ( ) → timestamp with time zone

目前日期和時間 (目前交易的開始時間);請參閱第 9.9.5 節

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

to_timestamp ( double precision ) → timestamp with time zone

將 Unix 時間戳記(自 1970-01-01 00:00:00+00 以來的秒數)轉換為含時區的時間戳記

to_timestamp(1284352323)2010-09-13 04:32:03+00


除了這些函數之外,還支援 SQL OVERLAPS 運算子

(start1, end1) OVERLAPS (start2, end2)
(start1, length1) OVERLAPS (start2, length2)

當兩個時間段(由其端點定義)重疊時,此運算式產生 true,當它們不重疊時,則產生 false。端點可以指定為日期、時間或時間戳記的配對;或作為日期、時間或時間戳記,後跟一個時間間隔。當提供一對值時,可以先寫開始或結束;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

interval 值加到(或從)timestamptimestamp with time zone 值時,會依次處理 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. EXTRACT, date_part #

EXTRACT(field FROM source)

extract 函數會從日期/時間值擷取子欄位,例如年或小時。source 必須是 timestampdatetimeinterval 類型的數值運算式。(時間戳記和時間可以帶或不帶時區。)field 是一個識別碼或字串,用於選取要從來源值擷取的欄位。並非所有欄位都對每個輸入資料類型有效;例如,無法從 date 擷取小於一天的欄位,而無法從 time 擷取一天或更多的欄位。extract 函數會傳回 numeric 類型的值。

以下是有效的欄位名稱

century

世紀;對於 interval 值,年份欄位除以 100

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
SELECT EXTRACT(CENTURY FROM DATE '0001-01-01 AD');
Result: 1
SELECT EXTRACT(CENTURY FROM DATE '0001-12-31 BC');
Result: -1
SELECT EXTRACT(CENTURY FROM INTERVAL '2001 years');
Result: 20
day

月份中的日期(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 以來的秒數(該時間戳記之前的時間戳記為負數);對於 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 將 epoch 值轉換回 timestamp with time zone

SELECT to_timestamp(982384720.12);
Result: 2001-02-17 04:38:40.12+00

請注意,將 to_timestamp 套用到從 datetimestamp 值擷取的 epoch 可能會產生誤導性的結果:結果實際上會假設原始值是以 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 相同。這與ISO8601 星期幾編號相符。

isoyear

ISO日期所屬的 ISO 8601 週編號年份

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

每個ISOISO 8601 週編號年份從包含 1 月 4 日的那一週的星期一開始,因此在一月初或十二月底,該ISO年份可能與格里高利曆的年份不同。更多資訊請參閱 week 欄位。

儒略日 (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)

千年;對於 interval 值,年份欄位除以 1000

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

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)

一年中的月份編號 (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
時區 (timezone)

與 UTC 的時區偏移量,以秒為單位。正值對應於 UTC 以東的時區,負值對應於 UTC 以西的時區。(技術上,PostgreSQL 不使用 UTC,因為它不處理閏秒。)

時區小時 (timezone_hour)

時區偏移量的小時部分

時區分鐘 (timezone_minute)

時區偏移量的分鐘部分

週 (week)

的編號ISOISO 8601 週編號年份的週數。 根據定義,ISO 週從星期一開始,並且一年中的第一週包含該年的 1 月 4 日。 換句話說,一年中的第一個星期四是該年的第 1 週。

在 ISO 週編號系統中,一月初的日期可能屬於前一年的第 52 或 53 週,而十二月底的日期可能屬於下一年的第一週。 例如,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
年份 (year)

年份欄位。 請記住沒有 0 AD,因此從 AD 年份中減去 BC 年份時應小心。

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

在處理 interval 值時,extract 函數產生與間隔輸出函數使用的解釋相符的欄位值。 如果從未規範化的間隔表示開始,這可能會產生令人驚訝的結果,例如

SELECT INTERVAL '80 minutes';
Result: 01:20:00
SELECT EXTRACT(MINUTES FROM INTERVAL '80 minutes');
Result: 20

注意

當輸入值為 +/-Infinity 時,對於單調遞增的欄位,extract 傳回 +/-Infinity (epochjulianyearisoyeardecadecenturymillennium 用於 timestamp 輸入;epochhourdayyeardecadecenturymillennium 用於 interval 輸入)。 對於其他欄位,傳回 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 ])

sourcetimestamptimestamp with time zoneinterval 類型的值運算式。(datetime 類型的值會自動轉換為 timestampinterval。)field 選擇要將輸入值截斷到的精確度。傳回值同樣是 timestamptimestamp with time zoneinterval 類型,並且它具有所有比所選值不重要的欄位都設定為零(或一天和一個月為一)。

field 的有效值為

微秒 (microseconds)
毫秒 (milliseconds)
秒 (second)
分鐘 (minute)
hour
day
週 (week)
月份 (month)
季度 (quarter)
年份 (year)
decade
century
千年 (millennium)

當輸入值為 timestamp with time zone 類型時,截斷會相對於特定時區執行;例如,截斷為 day 會產生該時區午夜的值。 預設情況下,截斷是相對於目前的 TimeZone 設定完成的,但是可以提供可選的 time_zone 引數來指定其他時區。 時區名稱可以使用 第 8.5.3 節中描述的任何方式來指定。

在處理 timestamp without time zoneinterval 輸入時,無法指定時區。 這些始終按其表面價值進行處理。

範例(假設本地時區是 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)

sourcetimestamptimestamp with time zone 類型的值運算式。(date 類型的值會自動轉換為 timestamp。)strideinterval 類型的值運算式。 傳回值同樣是 timestamptimestamp with time zone 類型,並且它標記了將 source 放置到的 bin 的開頭。

範例

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 and AT LOCAL #

AT TIME ZONE 運算子將時間戳記不帶時區與時間戳記時區之間相互轉換,並將 time with time zone 值轉換為不同的時區。 表 9.34 顯示了它的變體。

表 9.34. AT TIME ZONEAT LOCAL 變體

運算符

描述

範例

timestamp without time zone AT TIME ZONE zonetimestamp with time zone

將給定的時間戳記(不含時區資訊)轉換為時間戳記(時區資訊),並假設給定的值位於指定的時區。

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

timestamp without time zone AT LOCALtimestamp with time zone

將給定的時間戳記(不含時區資訊)轉換為時間戳記(時區資訊),並使用連線階段的 TimeZone 值作為時區。

timestamp '2001-02-16 20:38:40' at local2001-02-17 03:38:40+00

timestamp with time zone AT TIME ZONE zonetimestamp without time zone

將給定的時間戳記(時區資訊)轉換為時間戳記(不含時區資訊),呈現該時區所顯示的時間。

timestamp with time zone '2001-02-16 20:38:40-05' at time zone 'America/Denver'2001-02-16 18:38:40

timestamp with time zone AT LOCALtimestamp without time zone

將給定的時間戳記(時區資訊)轉換為時間戳記(不含時區資訊),呈現使用連線階段的 TimeZone 值作為時區所顯示的時間。

timestamp with time zone '2001-02-16 20:38:40-05' at local2001-02-16 18:38:40

time with time zone AT TIME ZONE zonetime with time zone

將給定的時間(時區資訊)轉換為新的時區。由於沒有提供日期,因此使用指定目標時區當前生效的 UTC 偏移量。

time with time zone '05:34:17-05' at time zone 'UTC'10:34:17+00

time with time zone AT LOCALtime with time zone

將給定的時間(時區資訊)轉換為新的時區。由於沒有提供日期,因此使用連線階段的 TimeZone 值當前生效的 UTC 偏移量。

假設連線階段的 TimeZone 設定為 UTC

time with time zone '05:34:17-05' at local10:34:17+00


在這些運算式中,所需的時區 zone 可以指定為文字值(例如,'America/Los_Angeles')或間隔(例如,INTERVAL '-08:00')。在文字的情況下,時區名稱可以用第 8.5.3 節中描述的任何方式指定。間隔的情況僅適用於與 UTC 具有固定偏移量的時區,因此在實務中並不常見。

語法 AT LOCAL 可以用作 AT TIME ZONE local 的簡寫,其中 local 是連線階段的 TimeZone 值。

範例(假設目前的 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
SELECT TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-05' AT LOCAL;
Result: 2001-02-16 17:38:40
SELECT TIME WITH TIME ZONE '20:38:40-05' AT LOCAL;
Result: 17:38:40

第一個範例為缺少時區資訊的值新增時區,並使用目前的 TimeZone 設定顯示該值。第二個範例將具有時區資訊的時間戳記值轉換為指定的時區,並傳回不含時區資訊的值。這允許儲存和顯示與目前的 TimeZone 設定不同的值。第三個範例將東京時間轉換為芝加哥時間。第四個範例將具有時區資訊的時間戳記值轉換為目前由 TimeZone 設定指定的時區,並傳回不含時區資訊的值。

第五個範例是一個警惕故事。由於輸入值沒有相關聯的日期,因此轉換是使用連線階段的目前日期進行的。因此,這個靜態範例可能會根據觀看年份的時間顯示錯誤的結果,因為 'America/Los_Angeles' 遵循日光節約時間。

函式 timezone(zone, timestamp) 等同於符合 SQL 標準的建構 timestamp AT TIME ZONE zone

函式 timezone(zone, time) 等同於符合 SQL 標準的建構 time AT TIME ZONE zone

函式 timezone(timestamp) 等同於符合 SQL 標準的建構 timestamp AT LOCAL

函式 timezone(time) 等同於符合 SQL 標準的建構 time AT LOCAL

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() 是傳統的 PostgreSQL,等同於 transaction_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 或其變體時,請確保您的會話持有的鎖定不要超過必要的數量。否則,其他會話可能必須等待您的休眠程序,從而減慢整個系統的速度。

提交更正

如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的地方,請使用此表單報告文件問題。