2025年9月25日: PostgreSQL 18 釋出!
支援版本:當前 (18) / 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

timestamp with time zone新增interval,根據第三個引數指定的時區或當前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

當向timestamptimestamp with time zone值新增(或從中減去)interval值時,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/Denver2005-04-03 02:00:00發生了夏令時更改,跳過了一個小時。

請注意,age 返回的months欄位可能存在歧義,因為不同的月份有不同的天數。PostgreSQL 的方法在計算部分月份時使用兩個日期中較早的那個月份。例如,age('2004-06-01', '2004-04-30') 使用四月得到 1 mon 1 day,而使用五月會得到 1 mon 2 days,因為五月有31天,而四月只有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將紀元值轉換回timestamp with time zone

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

請注意,將 to_timestamp 應用於從 datetimestamp 值中提取的紀元可能會產生誤導性結果:結果將有效假設原始值已在 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日期所屬的 8601 周編號年份

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

傳遞給 -c 的每個ISO8601 周編號年份從包含1月4日的星期一開始,因此在1月初或12月末,該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);對於interval值,為月份欄位除以3加1

SELECT EXTRACT(QUARTER FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 1
SELECT EXTRACT(QUARTER FROM INTERVAL '1 year 6 months');
Result: 3
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

本年度的ISO8601周編號周。根據定義,ISO周從星期一開始,一年的第一週包含當年的1月4日。換句話說,一年的第一個星期四屬於該年的第1周。

在 ISO 周編號系統中,一月初的日期可能屬於上一年的第 52 或 53 周,而十二月末的日期可能屬於下一年的第一週。例如,2005-01-01 屬於 2004 年的第 53 周,2006-01-01 屬於 2005 年的第 52 周,而 2012-12-31 屬於 2013 年的第一週。建議將 isoyear 欄位與 week 欄位一起使用以獲得一致的結果。

對於interval值,周欄位就是整數天數除以7。

SELECT EXTRACT(WEEK FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 7
SELECT EXTRACT(WEEK FROM INTERVAL '13 days 24 hours');
Result: 1
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 對單調遞增的欄位(timestamp 輸入的epochjulianyearisoyeardecadecenturymillenniuminterval 輸入的epochhourdayyeardecadecenturymillennium)返回 +/-Infinity。對於其他欄位,返回 NULL。PostgreSQL 9.6 之前的版本對於所有無限輸入情況都返回零。

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 ])

source 是型別為 timestamptimestamp 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所放置的箱子的開頭。

示例

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 ZONEAT 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 TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-05' AT TIME ZONE '+05';
Result: 2001-02-16 20:38:40
SELECT TIME WITH TIME ZONE '20:38:40-05' AT LOCAL;
Result: 17:38:40

第一個例子為缺少時區的值添加了一個時區,並使用當前TimeZone設定顯示該值。第二個例子將帶時區的時間戳值移到指定的時區,並返回不帶時區的值。這允許儲存和顯示不同於當前TimeZone設定的值。第三個例子將東京時間轉換為芝加哥時間。第四個例子將帶時區的時間戳值移到當前由TimeZone設定指定的時區,並返回不帶時區的值。第五個例子演示了POSIX風格時區規範中的符號與ISO-8601日期時間文字中的符號具有相反的含義,如第 8.5.3 節附錄 B所述。

第六個例子是一個警示。由於輸入值沒有關聯日期,因此使用會話的當前日期進行轉換。因此,這個靜態示例可能會根據檢視的時間顯示錯誤的結果,因為'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或其變體時,請確保您的會話持有的鎖不多於必要。否則,其他會話可能不得不等待您休眠的程序,從而減慢整個系統。

提交更正

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