9.9. Операторы и функции даты/времени
Все существующие функции для обработки даты/времени перечислены в Таблице 9.31, а подробнее они описаны в следующих подразделах. Поведение основных арифметических операторов (+
, *
и т. д.) описано в Таблице 9.30. Функции форматирования этих типов данных были перечислены в Разделе 9.8. Общую информацию об этих типах вы получили (или можете получить) в Разделе 8.5.
Помимо этого, для типов даты/времени имеются обычные операторы сравнения, показанные в Таблице 9.1. Значения даты и даты со временем (с часовым поясом или без него) можно сравнивать как угодно, тогда как значения только времени (с часовым поясом или без него) и интервалы допустимо сравнивать, только если их типы совпадают. При сравнении даты со временем без часового пояса и даты со временем с часовым поясом предполагается, что первое значение задано в часовом поясе, установленном параметром TimeZone, и оно пересчитывается в UTC для сравнения со вторым значением (внутри уже представленным в UTC). Аналогичным образом, при сравнении значений даты и даты со времени первое считается соответствующим полночи в часовом поясе TimeZone
.
Все описанные ниже функции и операторы, принимающие аргументы time
или timestamp
, фактически представлены в двух вариациях: одна принимает тип time with time zone
или timestamp with time zone
, а вторая — time without time zone
или timestamp without time zone
. Для краткости эти вариации здесь не разделяются. Кроме того, операторы +
и *
определяются парами, наделяющими их переместительным свойством (например, date
+
integer
и integer
+
date
); здесь приводится только один вариант для каждой пары.
Таблица 9.30. Операторы даты/времени
Оператор | Пример | Результат |
---|---|---|
+ | 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.31. Функции даты/времени
Функция | Тип результата | Описание | Пример | Результат |
---|---|---|---|---|
| interval | Вычитает аргументы и выдаёт «символический» результат с годами и месяцами, а не просто днями | age(timestamp '2001-04-10', timestamp '1957-06-13') | 43 years 9 mons 27 days (43 года 9 месяцев 27 дней) |
| interval | Вычитает дату/время из current_date (полночь текущего дня) | age(timestamp '1957-06-13') | 43 years 8 mons 3 days (43 года 8 месяцев 3 дня) |
| timestamp with time zone | Текущая дата и время (меняется в процессе выполнения операторов); см. Подраздел 9.9.4 | ||
| date | Текущая дата; см. Подраздел 9.9.4 | ||
| time with time zone | Текущее время суток; см. Подраздел 9.9.4 | ||
| timestamp with time zone | Текущая дата и время (на момент начала транзакции); см. Подраздел 9.9.4 | ||
| double precision | Возвращает поле даты (равнозначно extract ); см. Подраздел 9.9.1 | date_part('hour', timestamp '2001-02-16 20:38:40') | 20 |
| double precision | Возвращает поле даты (равнозначно extract ); см. Подраздел 9.9.1 | date_part('month', interval '2 years 3 months') | 3 |
| timestamp | Отсекает компоненты даты до заданной точности; см. Подраздел 9.9.2 | date_trunc('hour', timestamp '2001-02-16 20:38:40') | 2001-02-16 20:00:00 |
| 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 |
| interval | Отсекает компоненты даты до заданной точности; см. Подраздел 9.9.2 | date_trunc('hour', interval '2 days 3 hours 40 minutes') | 2 days 03:00:00 |
| double precision | Возвращает поле даты; см. Подраздел 9.9.1 | extract(hour from timestamp '2001-02-16 20:38:40') | 20 |
| double precision | Возвращает поле даты; см. Подраздел 9.9.1 | extract(month from interval '2 years 3 months') | 3 |
| boolean | Проверяет конечность даты (её отличие от +/-бесконечности) | isfinite(date '2001-02-16') | true |
| boolean | Проверяет конечность времени (его отличие от +/-бесконечности) | isfinite(timestamp '2001-02-16 21:28:30') | true |
| boolean | Проверяет конечность интервала | isfinite(interval '4 hours') | true |
| interval | Преобразует интервал так, что каждый 30-дневный период считается одним месяцем | justify_days(interval '35 days') | 1 mon 5 days (1 месяц 5 дней) |
| interval | Преобразует интервал так, что каждый 24-часовой период считается одним днём | justify_hours(interval '27 hours') | 1 day 03:00:00 (1 день 03:00:00) |
| interval | Преобразует интервал с применением justify_days и justify_hours и дополнительно корректирует знаки | justify_interval(interval '1 mon -1 hour') | 29 days 23:00:00 (29 дней 23:00:00) |
| time | Текущее время суток; см. Подраздел 9.9.4 | ||
| timestamp | Текущая дата и время (на момент начала транзакции); см. Подраздел 9.9.4 | ||
| date | Образует дату из полей: year (год), month (месяц) и day (день) | make_date(2013, 7, 15) | 2013-07-15 |
| interval | Образует интервал из полей: years (годы), months (месяцы), weeks (недели), days (дни), hours (часы), minutes (минуты) и secs (секунды) | make_interval(days => 10) | 10 days |
| time | Образует время из полей: hour (час), minute (минута) и sec (секунда) | make_time(8, 15, 23.5) | 08:15:23.5 |
| timestamp | Образует дату и время из полей: year (год), month (месяц), day (день), hour (час), minute (минута) и sec (секунда) | make_timestamp(2013, 7, 15, 8, 15, 23.5) | 2013-07-15 08:15:23.5 |
| timestamp with time zone | Образует дату и время с часовым поясом из полей: year (год), month (месяц), day (день), hour (час), minute (минута) и sec (секунда). Если параметр timezone (часовой пояс) не указан, используется текущий часовой пояс. | make_timestamptz(2013, 7, 15, 8, 15, 23.5) | 2013-07-15 08:15:23.5+01 |
| timestamp with time zone | Текущая дата и время (на момент начала транзакции); см. Подраздел 9.9.4 | ||
| timestamp with time zone | Текущая дата и время (на момент начала текущего оператора); см. Подраздел 9.9.4 | ||
| text | Текущая дата и время (как clock_timestamp , но в виде строки типа text ); см. Подраздел 9.9.4 | ||
| timestamp with time zone | Текущая дата и время (на момент начала транзакции); см. Подраздел 9.9.4 | ||
| timestamp with time zone | Преобразует время эпохи Unix (число секунд с 1970-01-01 00:00:00+00) в стандартное время | to_timestamp(1284352323) | 2010-09-13 04:32:03+00 |
В дополнение к этим функциям поддерживается SQL-оператор OVERLAPS
:
(начало1
,конец1
) OVERLAPS (начало2
,конец2
) (начало1
,длительность1
) OVERLAPS (начало2
,длительность2
)
Его результатом будет true, когда два периода времени (определённые своими границами) пересекаются, и false в противном случае. Границы периода можно задать либо в виде пары дат, времени или дат со временем, либо как дату, время (или дату со временем) c интервалом. Когда указывается пара значений, первым может быть и начало, и конец периода: OVERLAPS
автоматически считает началом периода меньшее значение. Периоды времени считаются наполовину открытыми, т. е. начало
<=
время
<
конец
, если только начало
и конец
не равны — в этом случае период представляет один момент времени. Это означает, например, что два периода, имеющие только общую границу, не будут считаться пересекающимися.
SELECT (DATE '2001-02-16', DATE '2001-12-21') OVERLAPS (DATE '2001-10-30', DATE '2002-10-30'); Результат:true
SELECT (DATE '2001-02-16', INTERVAL '100 days') OVERLAPS (DATE '2001-10-30', DATE '2002-10-30'); Результат:false
SELECT (DATE '2001-10-29', DATE '2001-10-30') OVERLAPS (DATE '2001-10-30', DATE '2001-10-31'); Результат:false
SELECT (DATE '2001-10-30', DATE '2001-10-30') OVERLAPS (DATE '2001-10-30', DATE '2001-10-31'); Результат:true
При добавлении к метке типа timestamp with time zone
значения interval
(или при вычитании из него interval
), поле дней в этой дате увеличивается (или уменьшается) на указанное число суток, а время суток остаётся неизменным. При пересечении границы перехода на летнее время (если в часовом поясе текущего сеанса производится этот переход) это означает, что interval '1 day'
и interval '24 hours'
не обязательно будут равны. Например, в часовом поясе America/Denver
:
SELECT timestamp with time zone '2005-04-02 12:00:00-07' + interval '1 day'; Результат:2005-04-03 12:00:00-06
SELECT timestamp with time zone '2005-04-02 12:00:00-07' + interval '24 hours'; Результат:2005-04-03 13:00:00-06
Эта разница объясняется тем, что 2005-04-03 02:00
в часовом поясе America/Denver
произошёл переход на летнее время.
Обратите внимание на возможную неоднозначность в поле months
в результате функции age
, вызванную тем, что число дней в разных месяцах неодинаково. Вычисляя оставшиеся дни месяца, PostgreSQL рассматривает месяц меньшей из двух дат. Например, результатом age('2004-06-01', '2004-04-30')
будет 1 mon 1 day
, так как в апреле 30 дней, а то же выражение с датой 30 мая выдаст 1 mon 2 days
, так как в мае 31 день.
Вычитание дат и дат со временем также может быть нетривиальной операцией. Один принципиально простой способ выполнить такое вычисление — преобразовать каждое значение в количество секунд, используя EXTRACT(EPOCH FROM ...)
, а затем найти разницу результатов; при этом будет получено число секунд между двумя датами. При этом будет учтено неодинаковое число дней в месяцах, изменения часовых поясов и переходы на летнее время. При вычитании дат или дат со временем с помощью оператора «-
» выдаётся число дней (по 24 часа) и часов/минут/секунд между данными значениями, с учётом тех же факторов. Функция age
возвращает число лет, месяцев, дней и часов/минут/секунд, выполняя вычитание по полям, а затем пересчитывая отрицательные значения. Различие этих подходов иллюстрируют следующие запросы. Показанные результаты были получены для часового пояса 'US/Eastern'
; между двумя заданными датами произошёл переход на летнее время:
SELECT EXTRACT(EPOCH FROM timestamptz '2013-07-01 12:00:00') - EXTRACT(EPOCH FROM timestamptz '2013-03-01 12:00:00'); Результат:10537200
SELECT (EXTRACT(EPOCH FROM timestamptz '2013-07-01 12:00:00') - EXTRACT(EPOCH FROM timestamptz '2013-03-01 12:00:00')) / 60 / 60 / 24; Результат:121.958333333333
SELECT timestamptz '2013-07-01 12:00:00' - timestamptz '2013-03-01 12:00:00'; Результат:121 days 23:00:00
SELECT age(timestamptz '2013-07-01 12:00:00', timestamptz '2013-03-01 12:00:00'); Результат:4 mons
9.9.1. EXTRACT
, date_part
EXTRACT(поле
FROMисточник
)
Функция extract
получает из значений даты/времени поля, такие как год или час. Здесь источник
— значение типа timestamp
, time
или interval
. (Выражения типа date
приводятся к типу timestamp
, так что допускается и этот тип.) Указанное поле
представляет собой идентификатор, по которому из источника выбирается заданное поле. Функция extract
возвращает значения типа double precision
. Допустимые поля:
century
Век:
SELECT EXTRACT(CENTURY FROM TIMESTAMP '2000-12-16 12:21:13'); Результат:
20
SELECT EXTRACT(CENTURY FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:21
Первый век начался 0001-01-01 00:00:00, хотя люди в то время и не считали так. Это определение распространяется на все страны с григорианским календарём. Века с номером 0 не было; считается, что 1 наступил после -1. Если такое положение вещей вас не устраивает, направляйте жалобы по адресу: Ватикан, Собор Святого Петра, Папе.
day
Для значений
timestamp
это день месяца (1 - 31), для значенийinterval
— число днейSELECT EXTRACT(DAY FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
16
SELECT EXTRACT(DAY FROM INTERVAL '40 days 1 minute'); Результат:40
decade
Год, делённый на 10
SELECT EXTRACT(DECADE FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
200
dow
День недели, считая с воскресенья (
0
) до субботы (6
)SELECT EXTRACT(DOW FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
5
Заметьте, что в
extract
дни недели нумеруются не так, как в функцииto_char(..., 'D')
.doy
День года (1 - 365/366)
SELECT EXTRACT(DOY FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
47
epoch
Для значений
timestamp with time zone
это число секунд с 1970-01-01 00:00:00 UTC (отрицательное для предшествующего времени); для значенийdate
иtimestamp
— номинальное число секунд с 1970-01-01 00:00:00 без учёта часового пояса, переходов на летнее время и т. п.; для значенийinterval
— общее количество секунд в интервалеSELECT EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40.12-08'); Результат:
982384720.12
SELECT EXTRACT(EPOCH FROM TIMESTAMP '2001-02-16 20:38:40.12'); Результат:982355920.12
SELECT EXTRACT(EPOCH FROM INTERVAL '5 days 3 hours'); Результат:442800
Преобразовать время эпохи назад, в значение
timestamp with time zone
, с помощьюto_timestamp
можно так:SELECT to_timestamp(982384720.12); Результат:
2001-02-17 04:38:40.12+00
Имейте в виду, что применяя
to_timestamp
к времени эпохи, извлечённому из значенияdate
илиtimestamp
, можно получить не вполне ожидаемый результат: эта функция подразумевает, что изначальное значение задано в часовом поясе UTC, но это может быть не так.hour
Час (0 - 23)
SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
20
isodow
День недели, считая с понедельника (
1
) до воскресенья (7
)SELECT EXTRACT(ISODOW FROM TIMESTAMP '2001-02-18 20:38:40'); Результат:
7
Результат отличается от
dow
только для воскресенья. Такая нумерация соответствует ISO 8601.isoyear
Год по недельному календарю ISO 8601, в который попадает дата (неприменимо к интервалам)
SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-01'); Результат:
2005
SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-02'); Результат:2006
Год по недельному календарю ISO начинается с понедельника недели, в которой оказывается 4 января, так что в начале января или в конце декабря год по ISO может отличаться от года по григорианскому календарю. Подробнее об этом рассказывается в описании поля
week
.Этого поля не было в PostgreSQL до версии 8.3.
julian
Юлианская дата, соответствующая дате или дате/времени (для интервала не определена). Значение будет дробным, если заданное время отличается от начала суток по местному времени. За дополнительной информацией обратитесь к Разделу B.7.
SELECT EXTRACT(JULIAN FROM DATE '2006-01-01'); Результат:
2453737
SELECT EXTRACT(JULIAN FROM TIMESTAMP '2006-01-01 12:00'); Результат:2453737.5
microseconds
Значение секунд с дробной частью, умноженное на 1 000 000; заметьте, что оно включает и целые секунды
SELECT EXTRACT(MICROSECONDS FROM TIME '17:12:28.5'); Результат:
28500000
millennium
Тысячелетие
SELECT EXTRACT(MILLENNIUM FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
3
Годы 20 века относятся ко второму тысячелетию. Третье тысячелетие началось 1 января 2001 г.
milliseconds
Значение секунд с дробной частью, умноженное на 1 000; заметьте, что оно включает и целые секунды.
SELECT EXTRACT(MILLISECONDS FROM TIME '17:12:28.5'); Результат:
28500
minute
Минуты (0 - 59)
SELECT EXTRACT(MINUTE FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
38
month
Для значений
timestamp
это номер месяца в году (1 - 12), а дляinterval
— остаток от деления числа месяцев на 12 (в интервале 0 - 11)SELECT EXTRACT(MONTH FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
2
SELECT EXTRACT(MONTH FROM INTERVAL '2 years 3 months'); Результат:3
SELECT EXTRACT(MONTH FROM INTERVAL '2 years 13 months'); Результат:1
quarter
Квартал года (1 - 4), к которому относится дата
SELECT EXTRACT(QUARTER FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
1
second
Секунды, включая дробную часть (0 - 59[7])
SELECT EXTRACT(SECOND FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
40
SELECT EXTRACT(SECOND FROM TIME '17:12:28.5'); Результат:28.5
timezone
Смещение часового пояса от UTC, представленное в секундах. Положительные значения соответствуют часовым поясам к востоку от UTC, а отрицательные — к западу. (Строго говоря, в PostgreSQL используется не UTC, так как секунды координации не учитываются.)
timezone_hour
Поле часов в смещении часового пояса
timezone_minute
Поле минут в смещении часового пояса
week
Номер недели в году по недельному календарю ISO 8601. По определению, недели ISO 8601 начинаются с понедельника, а первая неделя года включает 4 января этого года. Другими словами, первый четверг года всегда оказывается в 1 неделе этого года.
В системе нумерации недель ISO первые числа января могут относиться к 52-ой или 53-ей неделе предыдущего года, а последние числа декабря — к первой неделе следующего года. Например,
2005-01-01
относится к 53-ей неделе 2004 г., а2006-01-01
— к 52-ей неделе 2005 г., тогда как2012-12-31
включается в первую неделю 2013 г. Поэтому для получения согласованных результатов рекомендуется использовать полеisoyear
в паре сweek
.SELECT EXTRACT(WEEK FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
7
year
Поле года. Учтите, что года
0
не было, и это следует иметь в виду, вычитая из годов нашей эры годы до нашей эры.SELECT EXTRACT(YEAR FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
2001
Примечание
С аргументом +/-бесконечность extract
возвращает +/-бесконечность для монотонно увеличивающихся полей (epoch
, julian
, year
, isoyear
, decade
, century
и millennium
). Для других полей возвращается NULL. До версии 9.6 PostgreSQL возвращал ноль для всех случаев с бесконечными аргументами.
Функция extract
в основном предназначена для вычислительных целей. Функции форматирования даты/времени описаны в Разделе 9.8.
Функция date_part
эмулирует традиционный для Ingres эквивалент стандартной SQL-функции extract
:
date_part('поле
',источник
)
Заметьте, что здесь параметр поле
должен быть строковым значением, а не именем. Функция date_part
воспринимает те же поля, что и extract
.
SELECT date_part('day', TIMESTAMP '2001-02-16 20:38:40'); Результат:16
SELECT date_part('hour', INTERVAL '4 hours 3 minutes'); Результат:4
9.9.2. date_trunc
Функция date_trunc
работает подобно trunc
для чисел.
date_trunc(поле
,значение
[,часовой_пояс
])
Здесь значение
— выражение типа timestamp
, timestamp with time zone
или interval
. (Значения типов date
и time
автоматически приводятся к типам timestamp
и interval
, соответственно.) Параметр поле
определяет, до какой точности обрезать переданное значение. В возвращаемом значении, имеющем также тип timestamp
, timestamp with time zone
или interval
, все поля, менее значимые, чем заданное, будут равны нулю (или одному, если это номер дня или месяца).
Параметр поле
может принимать следующие значения:
microseconds |
milliseconds |
second |
minute |
hour |
day |
week |
month |
quarter |
year |
decade |
century |
millennium |
Когда входное значение имеет тип timestamp with time zone
, оно обрезается с учётом заданного часового пояса; например, если обрезать значение до поля day
(день), в результате будет получена полночь в этом часовом поясе. По умолчанию входное значение обрезается с учётом параметра TimeZone, но дополнительный аргумент часовой_пояс
позволяет выбрать и другой пояс. Название часового пояса может задаваться любым из способов, описанных в Подразделе 8.5.3.
Часовой пояс нельзя задать для значений типа timestamp without time zone
или interval
. Такие значения всегда воспринимаются как есть.
Несколько примеров (в предположении, что выбран часовой пояс America/New_York
):
SELECT date_trunc('hour', TIMESTAMP '2001-02-16 20:38:40'); Результат:2001-02-16 20:00:00
SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40'); Результат:2001-01-01 00:00:00
SELECT date_trunc('day', TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40+00'); Результат:2001-02-16 00:00:00-05
SELECT date_trunc('day', TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40+00', 'Australia/Sydney'); Результат:2001-02-16 08:00:00-05
SELECT date_trunc('hour', INTERVAL '3 days 02:47:33'); Результат:3 days 02:00:00
9.9.3. AT TIME ZONE
Указание AT TIME ZONE
позволяет переводить дату/время без часового пояса в дату/время с часовым поясом и обратно, а также пересчитывать значения времени для различных часовых поясов. Все разновидности этого указания проиллюстрированы в Таблице 9.32.
Таблица 9.32. Разновидности AT TIME ZONE
Выражение | Тип результата | Описание |
---|---|---|
| timestamp with time zone | Воспринимает заданное время без указания часового пояса как время в указанном часовом поясе |
| timestamp without time zone | Переводит данное значение timestamp с часовым поясом в другой часовой пояс, но не сохраняет информацию о нём в результате |
| time with time zone | Переводит данное время с часовым поясом в другой часовой пояс |
В этих выражениях желаемый часовой_пояс
можно задать либо в виде текстовой строки (например, 'America/Los_Angeles'
), либо как интервал (например, INTERVAL '-08:00'
). В первом случае название часового пояса можно указать любым из способов, описанных в Подразделе 8.5.3.
Примеры (в предположении, что местный часовой пояс America/Los_Angeles
):
SELECT TIMESTAMP '2001-02-16 20:38:40' AT TIME ZONE 'America/Denver'; Результат:2001-02-16 19:38:40-08
SELECT TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-05' AT TIME ZONE 'America/Denver'; Результат:2001-02-16 18:38:40
SELECT TIMESTAMP '2001-02-16 20:38:40-05' AT TIME ZONE 'Asia/Tokyo' AT TIME ZONE 'America/Chicago'; Результат:2001-02-16 05:38:40
В первом примере для значения, заданного без часового пояса, указывается часовой пояс и полученное время выводится в текущем часовом поясе (заданном параметром TimeZone
). Во втором примере значение времени смещается в заданный часовой пояс и выдаётся без указания часового пояса. Этот вариант позволяет хранить и выводить значения с часовым поясом, отличным от текущего. В третьем примере время в часовом поясе Токио пересчитывается для часового пояса Чикаго. При переводе значений времени без даты в другие часовые пояса используются определения часовых поясов, действующие в данный момент.
Функция
равнозначна SQL-совместимой конструкции timezone
(часовой_пояс
, время
)
.время
AT TIME ZONE часовой_пояс
9.9.4. Текущая дата/время
PostgreSQL предоставляет набор функций, результат которых зависит от текущей даты и времени. Все следующие функции соответствуют стандарту SQL и возвращают значения, отражающие время начала текущей транзакции:
CURRENT_DATE CURRENT_TIME CURRENT_TIMESTAMP CURRENT_TIME(точность
) CURRENT_TIMESTAMP(точность
) LOCALTIME LOCALTIMESTAMP LOCALTIME(точность
) LOCALTIMESTAMP(точность
)
CURRENT_TIME
и CURRENT_TIMESTAMP
возвращают время с часовым поясом. В результатах LOCALTIME
и LOCALTIMESTAMP
нет информации о часовом поясе.
CURRENT_TIME
, CURRENT_TIMESTAMP
, LOCALTIME
и LOCALTIMESTAMP
могут принимать необязательный параметр точности, определяющий, до какого знака после запятой следует округлять поле секунд. Если этот параметр отсутствует, результат будет иметь максимально возможную точность.
Несколько примеров:
SELECT CURRENT_TIME; Результат:14:39:53.662522-05
SELECT CURRENT_DATE; Результат:2001-12-23
SELECT CURRENT_TIMESTAMP; Результат:2001-12-23 14:39:53.662522-05
SELECT CURRENT_TIMESTAMP(2); Результат:2001-12-23 14:39:53.66-05
SELECT LOCALTIMESTAMP; Результат:2001-12-23 14:39:53.662522
Так как эти функции возвращают время начала текущей транзакции, во время транзакции эти значения не меняются. Это считается не ошибкой, а особенностью реализации: цель такого поведения в том, чтобы в одной транзакции «текущее» время было одинаковым и для разных изменений в одной транзакций записывалась одна отметка времени.
Примечание
В других СУБД эти значения могут изменяться чаще.
В PostgreSQL есть также функции, возвращающие время начала текущего оператора, а также текущее время в момент вызова функции. Таким образом, в 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'; -- см. замечание ниже
Подсказка
Не используйте третью форму для указания значения, которое будет вычисляться позднее, например, в предложении DEFAULT
для столбца таблицы. Система преобразует now
в значение timestamp
в момент разбора константы, поэтому когда будет вставляться такое значение по умолчанию, в соответствующем столбце окажется время создания таблицы! Первые две формы будут вычисляться, только когда значение по умолчанию потребуется, так как это вызовы функции. Поэтому они дадут желаемый результат при добавлении строки в таблицу. (См. также Подраздел 8.5.1.4.)
9.9.5. Задержка выполнения
В случае необходимости вы можете приостановить выполнение серверного процесса, используя следующие функции:
pg_sleep(сек
) pg_sleep_for(interval
) pg_sleep_until(timestamp with time zone
)
Функция pg_sleep
переводит процесс текущего сеанса в спящее состояние на указанное число секунд (сек
). Параметр сек
имеет тип double precision
, так что в нём можно указать и дробное число. Функция pg_sleep_for
введена для удобства, ей можно передать большие значения задержки в типе interval
. А pg_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
или её вариации, убедитесь в том, что в текущем сеансе нет ненужных блокировок. В противном случае в состояние ожидания могут перейти и другие сеансы, так что это отразится на системе в целом.