PostgreSQL range docs suggest that the magic timestamp infinity
should work the same as omitting the bounding value:
Element types that have the notion of “infinity” can use them as explicit bound values. For example, with timestamp ranges,
[today,infinity)
excludes the special timestamp value infinity, while[today,infinity]
include it, as does[today,)
and[today,]
.The functions lower_inf and upper_inf test for infinite lower and upper bounds of a range, respectively.
Yet when using upper_inf
to test whether the range (or multirange) includes infinity, the result is always false with the infinity
in place:
SELECT * FROM (
SELECT 1 AS test, upper_inf('{(,)}'::tstzmultirange)
UNION SELECT 2, upper_inf('{(,infinity)}'::tstzmultirange)
UNION SELECT 3, upper_inf('{(,]}'::tstzmultirange)
UNION SELECT 4, upper_inf('{(,infinity]}'::tstzmultirange)
UNION SELECT 5, upper_inf('(,)'::tstzrange)
UNION SELECT 6, upper_inf('(,infinity)'::tstzrange)
UNION SELECT 7, upper_inf('(,]'::tstzrange)
UNION SELECT 8, upper_inf('(,infinity]'::tstzrange)
) AS cases ORDER BY test;
Produces:
1 true
2 false
3 true
4 false
5 true
6 false
7 true
8 false
Why?
Adrian Klaver correctly pointed out another section of the docs that I have missed:
upper_inf ( anyrange ) → boolean
Does the range have no upper bound? (An upper bound of Infinity returns false.)
upper_inf('(,)'::daterange) → t
So, upper_inf
tests whether the upper bound is explicitly set, rather than what it is.
Infinity means "unlimited", so the "end value of the range" effectively doesn't exist (any value above the lower end will be within the range). Still, the range itself defines infinity as its upper end, so technically speaking, the upper bound is set.
It kind of makes sense. But it's also rather confusing.