Firstly the answer to this could be generic or plain sql, however I'm developing it in postgresql 9.3.x and will present the setup in this format as it has some handy tsrange data types.
I have a requirement to retrieve a timestamp given:
- a starting timestamp
- duration (interval)
- a set of timestamp ranges.
A working scenario for this would be calculating 24h from now (business hours only), today being Friday at 1300, the result would be next Thursday at 1300 (6 active working hours per day).
A very detailed answer provided by Erwin Brandstetter to a similar question can be found here.
To make replying easier I'll create a scenario:
Let's create a table with timestamp ranges in postgresql and populate them with some data
CREATE TABLE working_hours (id serial NOT NULL, trange tstzrange NOT NULL, CONSTRAINT whours_pkey PRIMARY KEY (id));
INSERT INTO working_hours (trange) VALUES
('[2014-05-01 09:30:00+07, 2014-05-01 11:30:00+07]'),('[2014-05-01 13:00:00+07,2014-05-01 17:00:00+07]'),
('[2014-05-02 09:30:00+07, 2014-05-02 11:30:00+07]'),('[2014-05-02 13:00:00+07,2014-05-02 17:00:00+07]'),
('[2014-05-05 09:30:00+07, 2014-05-05 11:30:00+07]'),('[2014-05-05 13:00:00+07,2014-05-05 17:00:00+07]'),
('[2014-05-06 09:30:00+07, 2014-05-06 11:30:00+07]'),
('[2014-05-07 09:30:00+07, 2014-05-07 11:30:00+07]'),('[2014-05-07 13:00:00+07,2014-05-07 17:00:00+07]'),
('[2014-05-08 09:30:00+07, 2014-05-08 11:30:00+07]'),('[2014-05-08 13:00:00+07,2014-05-08 17:00:00+07]'),
('[2014-05-09 09:30:00+07, 2014-05-09 11:30:00+07]'),('[2014-05-09 13:00:00+07,2014-05-09 17:00:00+07]'),
('[2014-05-10 09:30:00+07, 2014-05-10 11:30:00+07]'),('[2014-05-10 13:00:00+07,2014-05-10 17:00:00+07]');
I feel this can be achieved through a SELECT statement rather than a function that has a loop in it.
My idea of this statement would be 2 or 3 parts:
Firstly minus the remainder of the duration from 'trange', returning the id of the last trange to affect the duration with the remainder being >= 0.
Secondly add the remainder as interval to either lower(trange) or upper(trange) dependent on the remainder falling in or out of the last trange.
Here are the reference pages for Postgresql Range Types and Range Functions & Operators.
I appreciate any feedback on this, even if it is a completely different way to tackle the challenge. Though I posted this as Postgresql 9.3, the answer could be any language or language agnostic.