A: 

I came up with a pseudocode solution, hope it helps.

create an array named timetable with 24 entries
initialise timetable to zero

for each user in SQLtable
  firsthour = user.firsthour
  lasthour = user.lasthour

  firstminutes = 4 - (rounded down integer(user.firstminutes/15))
  lastminutes = rounded down integer(user.lastminutes/15)

  timetable(firsthour) = timetable(firsthour) + firstminutes
  timetable(lasthour) = timetable(lasthour) + lastminutes

  for index=firsthour+1 to lasthour-1
    timetable(index) = timetable(index) + 4
  next index

next user

Now the timetable array holds the values you desire in 15 minute granularity, ie. a value of 4 = 1 hour, 5 = 1 hour 15 minutes, 14 = 3 hours 30 minutes.

+1  A: 

Create a table with just time in it from midnight to midnight containing each minute of the day. In the data warehouse world we would call this a time dimension. Here's an example:

TIME_DIM
 -id
 -time_of_day
 -interval_15 
 -interval_30

an example of the data in the table would be

id   time_of_day    interval_15    interval_30
1    00:00          00:00          00:00
...
30   00:23          00:15          00:00
...
100  05:44          05:30          05:30

Then all you have to do is join your table to the time dimension and then group by interval_15. For example:

SELECT b.interval_15, count(*) 
FROM my_data_table a
INNER JOIN time_dim b ON a.time_field = b.time
WHERE a.date_field = now()
GROUP BY b.interval_15
Mike Farmer
Shouldn't your join look like: INNER JOIN time_dim b ON (a.start_time <= b.time AND a.end_time >= b.time)And, you would want to divide the count(*) value by 15 to get "man-quarter-hours" (i.e. how many whole men per 15 minute period). If you were looking for man-hours you would divide by 60.
Prestaul
Together you and Mike have answered it. Thank you!
willpall
A: 

Here's another pseudocode solution from a different angle; a bit more intensive because it does 96 queries for every 24hr period:

results = []
for time in range(0, 24, .25):
  amount = mysql("select count(*) from User_Activity_Table where time >= start_time and time <= end_time")
  results.append(amount)
pjz
This one popped into my head an hour after posting the question. For the amount of data I'm crunching (not that much) I would have no problems churning through a bunch or queries. Might want to change time <= end_time to time < end_time to avoid double-counts.
willpall
A: 

How about this:

Use that "times" table, but with two columns, containing the 15-minute intervals. The from_times are the 15-minutely times, the to_times are a second before the next from_times. For example 12:30:00 to 12:44:59.

Now get your person work table, which I've called "activity" here, with start_time and end_time columns.

I added values for Alice and Bob as per the original question.

Here's the query from MySQL:

SELECT HOUR(times.from_time) AS 'TIME', count(*) / 4 AS 'HOURS'
FROM times
  JOIN activity
  ON times.from_time >= activity.start_time AND 
     times.to_time   <= activity.end_time
GROUP BY HOUR(times.from_time)
ORDER BY HOUR(times.from_time)

which gives me this:

TIME   HOURS
12     0.7500
13     1.0000
14     1.0000
15     1.5000
16     2.0000
17     1.0000
18     1.0000
19     0.7500

Looks about right...

Mike Woodhouse