Когда интервал представляет собой разницу между двумя временными метками, он всегда выравнивается до часов (т. е. имеет стандартный формат). Примеры:
select
'2015-01-01 13:0:0'::timestamp - '2014-01-01 23:0:0'::timestamp, --> 364 days 14:00:00
'2015-01-01 13:0:0'::timestamp - '2014-01-01 03:0:0'::timestamp, --> 365 days 10:00:00
'2015-01-01 13:0:0'::timestamp - '2015-01-01 03:0:0'::timestamp; --> 10:00:00
Вычисления на интервалах выполняются отдельно для части даты и части времени, поэтому они могут привести к странным форматам. Примеры:
select
'2 day 1:00:00'::interval- '1 day 2:00:00'::interval, --> 1 day -01:00:00 (!!)
'2 day 100:00:00'::interval+ '1 day 60:00:00'::interval, --> 3 days 160:00:00
'2 day 100:00:00'::interval- '2 day 60:00:00'::interval; --> 40:00:00
Для таких случаев разработчики Postgres предусмотрели соответствующую функцию стандартизации формата:
select
justify_hours('1 day -01:00:00'), --> 23:00:00
justify_hours('3 days 160:00:00'), --> 9 days 16:00:00
justify_hours('40:00:00'); --> 1 day 16:00:00
Однако они не думали, что потребуется обратная операция. В этом ответе я предложил функцию для преобразования части даты интервала в часы. Я думаю, что это может быть (с небольшими изменениями) какая-то обратная функция для justify_hours()
:
create or replace function unjustify_hours(interval)
returns interval language sql as $$
select format('%s:%s',
(extract (epoch from $1) / 3600)::int,
to_char($1, 'mi:ss'))::interval;
$$;
select
unjustify_hours('23:00:00'), --> 23:00:00
unjustify_hours('9 days 16:00:00'), --> 232:00:00
unjustify_hours('1 day 16:00:00'); --> 40:00:00
Функция to_char(interval, text)
тут не поможет, т.к.
select
to_char(interval '23:00:00', 'hh24:mi:ss'), --> 23:00:00
to_char(interval '9 days 16:00:00', 'hh24:mi:ss'), --> 16:00:00 (!)
to_char(interval '1 day 16:00:00', 'hh24:mi:ss'); --> 16:00:00 (!)
Обратите внимание, что интервал может быть правильно отформатирован разными способами:
select
justify_hours('100:00:00'), --> 4 days 04:00:00
justify_hours('1 days 76:00:00'), --> 4 days 04:00:00
justify_hours('2 days 52:00:00'), --> 4 days 04:00:00
justify_hours('5 days -20:00:00'); --> 4 days 04:00:00
Согласно документации:
В соответствии со стандартом SQL все поля значения интервала должны иметь один и тот же знак, поэтому ко всем полям применяется начальный отрицательный знак; например, отрицательный знак в литеральном интервале '-1 2:03:04' применяется как к дням, так и к часам/минутам/секундам. PostgreSQL позволяет полям иметь разные знаки и традиционно рассматривает каждое поле в текстовом представлении как независимо подписанное, так что в этом примере час/минута/секунда считается положительной. Если для IntervalStyle задано значение sql_standard, то считается, что ведущий знак применяется ко всем полям (но только в том случае, если не отображаются дополнительные знаки). В противном случае используется традиционная интерпретация PostgreSQL. Во избежание двусмысленности рекомендуется прикреплять явный знак к каждому полю, если какое-либо поле отрицательное.
а также
Внутренние значения интервалов хранятся в виде месяцев, дней и секунд. Это делается потому, что количество дней в месяце варьируется, и в сутках может быть 23 или 25 часов, если задействована корректировка летнего времени. Поля месяцев и дней представляют собой целые числа, а поле секунд может хранить дроби. Поскольку интервалы обычно создаются из строк-констант или вычитания временных меток, в большинстве случаев этот метод хранения работает хорошо. Функции justify_days и justify_hours доступны для настройки дней и часов, которые выходят за пределы их обычных диапазонов.
person
klin
schedule
29.06.2016