And the end of the day, they ended up selecting all the start and end dates and then building their own interval tree ( https://en.wikipedia.org/wiki/Interval_tree ) and doing overlap detection themselves.
If they were using a database with good stored procedure support and had the skills to write the stored procedure or function in the database, they might then fight with writing the overlap detection there... but they likely found it a profoundly unpleasant experience.
And then here's PostgreSQL. It has it native. Hours, days, weeks of time spent writing, testing, debugging and otherwise fighting with this problem now suddenly become something along the lines of "SELECT isempty(daterange('2017-04-30', '2017-05-07')) FROM reservations" or something to that effect.
It represents a significant time savings when you need it for things that are more interesting than reimplementing data structures that aren't in the standard libraries.
create table reservation1 (duration tstzrange);
select * from reservation1 where duration && '[2017-04-30, 2017-05-07]';
create table reservation2 (start timestamptz, stop timestamptz, check (start <= stop));
select * from reservation2 where '2017-04-30' <= stop and start <= '2017-05-07';
create table reservation1 (duration tsrange, exclude using gist (duration with &&));
insert into reservation1 values ('[2017-04-30, 2017-05-07]'); -- ok
insert into reservation1 values ('[2017-05-10, 2017-05-12]'); -- ok
insert into reservation1 values ('[2017-05-05, 2017-05-08]'); -- error!
No index (start, stop) 123ms
Btree index (start, stop) 29ms
GIST index (duration) 0.2ms