9.9. Операторы и функции даты/времени
Все существующие функции для обработки даты/времени перечислены в Таблице 9.30, а подробнее они описаны в следующих подразделах. Поведение основных арифметических операторов (+, * и т. д.) описано в Таблице 9.29. Функции форматирования этих типов данных были перечислены в Разделе 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.29. Операторы даты/времени
| Оператор | Пример | Результат |
|---|---|---|
+ | 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.30. Функции даты/времени
| Функция | Тип результата | Описание | Пример | Результат |
|---|---|---|---|---|
| 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 |
| 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-06SELECT 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 mons9.9.1. EXTRACT, date_part
EXTRACT(fieldFROMsource)
Функция extract получает из значений даты/времени поля, такие как год или час. Здесь источник — значение типа timestamp, time или interval. (Выражения типа date приводятся к типу timestamp, так что допускается и этот тип.) Указанное поле представляет собой идентификатор, по которому из источника выбирается заданное поле. Функция extract возвращает значения типа double precision. Допустимые поля:
centuryВек:
SELECT EXTRACT(CENTURY FROM TIMESTAMP '2000-12-16 12:21:13'); Результат:
20SELECT 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'); Результат:
16SELECT EXTRACT(DAY FROM INTERVAL '40 days 1 minute'); Результат:40decadeГод, делённый на 10
SELECT EXTRACT(DECADE FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
200dowДень недели, считая с воскресенья (
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'); Результат:
47epochДля значений
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.12SELECT EXTRACT(EPOCH FROM TIMESTAMP '2001-02-16 20:38:40.12'); Результат:982355920.12SELECT 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'); Результат:
20isodowДень недели, считая с понедельника (
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'); Результат:
2005SELECT 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'); Результат:
2453737SELECT EXTRACT(JULIAN FROM TIMESTAMP '2006-01-01 12:00'); Результат:2453737.5microsecondsЗначение секунд с дробной частью, умноженное на 1 000 000; заметьте, что оно включает и целые секунды
SELECT EXTRACT(MICROSECONDS FROM TIME '17:12:28.5'); Результат:
28500000millenniumТысячелетие
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'); Результат:
28500minuteМинуты (0 - 59)
SELECT EXTRACT(MINUTE FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
38monthДля значений
timestampэто номер месяца в году (1 - 12), а дляinterval— остаток от деления числа месяцев на 12 (в интервале 0 - 11)SELECT EXTRACT(MONTH FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
2SELECT EXTRACT(MONTH FROM INTERVAL '2 years 3 months'); Результат:3SELECT EXTRACT(MONTH FROM INTERVAL '2 years 13 months'); Результат:1quarterКвартал года (1 - 4), к которому относится дата
SELECT EXTRACT(QUARTER FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
1secondСекунды, включая дробную часть (0 - 59[7])
SELECT EXTRACT(SECOND FROM TIMESTAMP '2001-02-16 20:38:40'); Результат:
40SELECT EXTRACT(SECOND FROM TIME '17:12:28.5'); Результат:28.5timezoneСмещение часового пояса от 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'); Результат:
7yearПоле года. Учтите, что года
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');
Результат:49.9.2. date_trunc
Функция date_trunc работает подобно trunc для чисел.
date_trunc('поле', значение)
Здесь значение — это выражение типа timestamp или interval. (Значения типов date и time автоматически приводятся к типам timestamp и interval, соответственно.) Параметр поле определяет, до какой точности обрезать переданное значение. Возвращаемое значение будет иметь тип timestamp или interval и все его значения, менее значимые, чем заданное поле, будут равны нулю (или единице, если это номер дня или месяца).
Параметр поле может принимать следующие значения:
microseconds |
milliseconds |
second |
minute |
hour |
day |
week |
month |
quarter |
year |
decade |
century |
millennium |
Примеры:
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
9.9.3. AT TIME ZONE
Указание AT TIME ZONE позволяет переводить дату/время без часового пояса в дату/время с часовым поясом и обратно, а также пересчитывать значения времени для различных часовых поясов. Все разновидности этого указания проиллюстрированы в Таблице 9.31.
Таблица 9.31. Разновидности 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-08SELECT TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-05' AT TIME ZONE 'America/Denver'; Результат:2001-02-16 18:38:40SELECT 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-05SELECT CURRENT_DATE; Результат:2001-12-23SELECT CURRENT_TIMESTAMP; Результат:2001-12-23 14:39:53.662522-05SELECT CURRENT_TIMESTAMP(2); Результат:2001-12-23 14:39:53.66-05SELECT 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 или её вариации, убедитесь в том, что в текущем сеансе нет ненужных блокировок. В противном случае в состояние ожидания могут перейти и другие сеансы, так что это отразится на системе в целом.