问题
How can I determine the largest resolution of an INTERVAL value? For example:
INTERVAL '100 days and 3 seconds'
=> dayTIME '20:05' - TIME '12:01:01'
=> hourAGE(NOW(), NOW() - INTERVAL '1 MONTH')
=> month
回答1:
The question isn't 100% clear so the answer may or may not be exactly what you're looking for, but...
There is a justify_interval() function, which you might want to look into.
test=# select justify_interval(INTERVAL '100 days 3 seconds');
justify_interval
-------------------------
3 mons 10 days 00:00:03
(1 row)
test=# select justify_interval(TIME '20:05' - TIME '12:01:01');
justify_interval
------------------
08:03:59
(1 row)
test=# select justify_interval(AGE(NOW(), NOW() - INTERVAL '1 MONTH'));
justify_interval
------------------
1 mon
(1 row)
For there extract the year, then month, then day, etc. until you come up with a non-zero answer:
test=# select extract('mon' from interval '3 mons 10 days 00:00:03');
date_part
-----------
3
Re your other question in comments:
create function max_res(interval) returns interval as $$
select case
when extract('year' from justify_interval($1)) > 0 or
extract('mon' from justify_interval($1)) > 0 or
extract('day' from justify_interval($1)) > 0
then '1 day'
when extract('hour' from justify_interval($1)) > 0
then '1 hour'
when ...
end;
$$ language sql immutable strict;
回答2:
INTERVAL is 12 bytes and is a struct containing months, days and microseconds and has a range of +/- 178000000 years. It always has a fixed max size of 178000000 years due to the way that it stores this information.
Be careful with your understanding of "a month" because the Julian month is not a constant in the same way that an hour
or a minute
is (e.g. how many days are in the month of February? Or how many days are there in a year
? It's not always 30 or 365 in reality and PostgreSQL updates things correctly. per an interesting conversation on IRC, Adding 1 month
::INTERVAL to January 30th will result in whatever the last day of February because it increments the tm_mon
member of struct tm
(and in this case, rolls back to the previous valid date).
Ah ha! I get the question now (or at least I think so). You're looking to determine the largest "non-zero integer unit" for a given INTERVAL
.
PostgreSQL doesn't have a built-in function that returns that information. I think you're going to have to chain a conditional and return type. Some example PL
code:
t := EXTRACT(EPOCH FROM my_time_input);
IF t >= 31104000 THEN
RETURN 'year';
ELSIF t >= 2592000 THEN
RETURN 'month';
ELSIF t >= 604800 THEN
RETURN 'week';
ELSIF t >= 86400 THEN
RETURN 'day';
ELSIF t >= 3600 THEN
RETURN 'hour';
ELSIF t >= 60 THEN
RETURN 'minute'
ELSIF t > 1 THEN
RETURN 'seconds';
ELSIF t == 1 THEN
RETURN 'second';
ELSE
RETURN resolve_largest_sub_second_unit(my_time);
END IF;
来源:https://stackoverflow.com/questions/6374453/how-to-determine-largest-resolution-of-an-interval