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. Функции даты/времени

ФункцияТип результатаОписаниеПримерРезультат
age(timestamp, timestamp)intervalВычитает аргументы и выдаёт «символический» результат с годами и месяцами, а не просто днямиage(timestamp '2001-04-10', timestamp '1957-06-13')43 years 9 mons 27 days (43 года 9 месяцев 27 дней)
age(timestamp)intervalВычитает дату/время из current_date (полночь текущего дня)age(timestamp '1957-06-13')43 years 8 mons 3 days (43 года 8 месяцев 3 дня)
clock_timestamp()timestamp with time zoneТекущая дата и время (меняется в процессе выполнения операторов); см. Подраздел 9.9.4  
current_datedateТекущая дата; см. Подраздел 9.9.4  
current_timetime with time zoneТекущее время суток; см. Подраздел 9.9.4  
current_timestamptimestamp with time zoneТекущая дата и время (на момент начала транзакции); см. Подраздел 9.9.4  
date_part(text, timestamp)double precisionВозвращает поле даты (равнозначно extract); см. Подраздел 9.9.1date_part('hour', timestamp '2001-02-16 20:38:40')20
date_part(text, interval)double precisionВозвращает поле даты (равнозначно extract); см. Подраздел 9.9.1date_part('month', interval '2 years 3 months')3
date_trunc(text, timestamp)timestampОтсекает компоненты даты до заданной точности; см. Подраздел 9.9.2date_trunc('hour', timestamp '2001-02-16 20:38:40')2001-02-16 20:00:00
date_trunc(text, timestamp with time zone, text)timestamp with time zoneОтсекает компоненты даты до заданной точности в указанном часовом поясе; см. Подраздел 9.9.2date_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.2date_trunc('hour', interval '2 days 3 hours 40 minutes')2 days 03:00:00
extract(field from timestamp)double precisionВозвращает поле даты; см. Подраздел 9.9.1extract(hour from timestamp '2001-02-16 20:38:40')20
extract(field from interval)double precisionВозвращает поле даты; см. Подраздел 9.9.1extract(month from interval '2 years 3 months')3
isfinite(date)booleanПроверяет конечность даты (её отличие от +/-бесконечности)isfinite(date '2001-02-16')true
isfinite(timestamp)booleanПроверяет конечность времени (его отличие от +/-бесконечности)isfinite(timestamp '2001-02-16 21:28:30')true
isfinite(interval)booleanПроверяет конечность интервалаisfinite(interval '4 hours')true
justify_days(interval)intervalПреобразует интервал так, что каждый 30-дневный период считается одним месяцемjustify_days(interval '35 days')1 mon 5 days (1 месяц 5 дней)
justify_hours(interval)intervalПреобразует интервал так, что каждый 24-часовой период считается одним днёмjustify_hours(interval '27 hours')1 day 03:00:00 (1 день 03:00:00)
justify_interval(interval)intervalПреобразует интервал с применением justify_days и justify_hours и дополнительно корректирует знакиjustify_interval(interval '1 mon -1 hour')29 days 23:00:00 (29 дней 23:00:00)
localtimetimeТекущее время суток; см. Подраздел 9.9.4  
localtimestamptimestampТекущая дата и время (на момент начала транзакции); см. Подраздел 9.9.4  
make_date(year int, month int, day int) dateОбразует дату из полей: year (год), month (месяц) и day (день)make_date(2013, 7, 15)2013-07-15
make_interval(years int DEFAULT 0, months int DEFAULT 0, weeks int DEFAULT 0, days int DEFAULT 0, hours int DEFAULT 0, mins int DEFAULT 0, secs double precision DEFAULT 0.0) intervalОбразует интервал из полей: years (годы), months (месяцы), weeks (недели), days (дни), hours (часы), minutes (минуты) и secs (секунды)make_interval(days => 10)10 days
make_time(hour int, min int, sec double precision) timeОбразует время из полей: hour (час), minute (минута) и sec (секунда)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Образует дату и время из полей: year (год), month (месяц), day (день), hour (час), minute (минута) и sec (секунда)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Образует дату и время с часовым поясом из полей: year (год), month (месяц), day (день), hour (час), minute (минута) и sec (секунда). Если параметр timezone (часовой пояс) не указан, используется текущий часовой пояс.make_timestamptz(2013, 7, 15, 8, 15, 23.5)2013-07-15 08:15:23.5+01
now()timestamp with time zoneТекущая дата и время (на момент начала транзакции); см. Подраздел 9.9.4  
statement_timestamp()timestamp with time zoneТекущая дата и время (на момент начала текущего оператора); см. Подраздел 9.9.4  
timeofday()textТекущая дата и время (как clock_timestamp, но в виде строки типа text); см. Подраздел 9.9.4  
transaction_timestamp()timestamp with time zoneТекущая дата и время (на момент начала транзакции); см. Подраздел 9.9.4  
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:

(начало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(field FROM source)

Функция 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 without time zone AT TIME ZONE часовой_поясtimestamp with time zoneВоспринимает заданное время без указания часового пояса как время в указанном часовом поясе
timestamp with time zone AT TIME ZONE часовой_поясtimestamp without time zoneПереводит данное значение timestamp с часовым поясом в другой часовой пояс, но не сохраняет информацию о нём в результате
time with time zone AT TIME ZONE часовой_пояс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). Во втором примере значение времени смещается в заданный часовой пояс и выдаётся без указания часового пояса. Этот вариант позволяет хранить и выводить значения с часовым поясом, отличным от текущего. В третьем примере время в часовом поясе Токио пересчитывается для часового пояса Чикаго. При переводе значений времени без даты в другие часовые пояса используются определения часовых поясов, действующие в данный момент.

Функция timezone(часовой_пояс, время) равнозначна SQL-совместимой конструкции время 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 или её вариации, убедитесь в том, что в текущем сеансе нет ненужных блокировок. В противном случае в состояние ожидания могут перейти и другие сеансы, так что это отразится на системе в целом.



[7] 60, если операционная система поддерживает секунды координации