Here's another way I found (via Mysql filling in missing dates ). Create 3 tables: vehicles, firm bookings only and all available dates for the year.
reservations: id, booked, vehicle_ref
insert into reservations values (0, '2011-01-12',1);
insert into reservations values (0, '2011-01-13',1);
insert into reservations values (0, '2011-01-14',1);
insert into reservations values (0, '2011-01-20',1);
insert into reservations values (0, '2011-01-21',1);
reservations_free: free (just a list of all dates this year...)
insert into reservations_free values
('2011-01-10'),
('2011-01-11'),
('2011-01-12'),
('2011-01-13'),
('2011-01-14'),
('2011-01-15'),
('2011-01-16'),
('2011-01-17'),
('2011-01-18'),
('2011-01-19'),
('2011-01-20'),
('2011-01-21'),
('2011-01-22'),
('2011-01-23');
Retrieve all dates which are not booked for vehicle #1 between 1 jan and 1 feb:
SELECT free
FROM reservations_free
LEFT OUTER JOIN reservations ON (reservations.booked = reservations_free.free AND reservations.vehicle_ref =1)
WHERE booked IS NULL AND
reservations_free.free
BETWEEN '2011-01-01'
AND '2011-02-01'
ORDER BY free
LIMIT 0 , 30;
Gets you the list:
2011-01-10
2011-01-11
2011-01-15
2011-01-16
2011-01-17
2011-01-18
2011-01-19
2011-01-22
2011-01-23
Of course you'd have to maintain the reservations_free table every year, that sql statement might need further optimising as I only fiddled with it from the original.
Using mysql DATE fields means you can browse your data and it will still make some sense to you as a human.
Adding and deleting a day would be a cinch.
It does not deliver the "free between 15th and 19th Jan" as asked for, but that should be doable in PHP, if not in a slightly more complex sql statement.