Find best suitable time from given time interval of different users.
Rows: 5
fid userid FromDateTime ToDateTime flag
62 1 2012-07-18 01:48:20 2012-07-18 02:55:20 1
63 1 2012-07-18 10:30:46 2012-07-18 12:54:46 1
64 1 2012-07-18 18:50:24 2012-07-18 20:35:24 1
67 1 2012-07-18 15:03:36 2012-07-18 16:03:36 1
68 2 2012-07-18 21:10:47 2012-07-18 23:10:47 1
Above table show different free timesperiods available for different user, for examaple:
user1
is free in
2012-07-18 01:48:20 to 2012-07-18 02:55:20 ,
2012-07-18 10:30:46 to 2012-07-18 12:54:46
......
user 2
is only free between this time period:
2012-07-18 21:10:47 to 2012-07-18 23:10:47
Now I want to find out one best time interval in which both user can schedule their meeting.
To find when both user1 and user2 are free, please try below:
SQL FIDDLE HERE.
EDITED: For comparing more than 2 users,pls try below:
Need to change
m.userid in (2,4,3,5)
andhaving count(rn)=4
according to number of users.SQL FIDDLE HERE
I have found a hacky way to do this :
Perl has some thing called
Set::IntSpan
which has aintersect
function(or method) that will find a range common to two intervals of numbers. The idea is to make use of it.You can convert date time strings to timestamp(numbers) using
strtotime("2012-08-27 02:02:02")
in php. Once you have two pairs of timestamps, you can use the following sample perl code to find the intersection interval from which you can find the time.once you have the intersecting interval, you can get back the date time from timestamp (if you need) using
date("Y-m-d H:i:s", $timestamp);
Here are some related links and references:
Calculate overlap between 2 ranges of numbers
Calling Perl script from PHP and passing in variables, while also using variablized perl script name
p.s. perhaps perl pros can wrap up the code into a function with 4 arguments? also, i understand this isn't the perfect answer to the question but imo the idea is cool.
You can use this solution to find the "best" time window in which ALL users in your criteria (let's say
userids
1-5) can meet. The "best" time window is measured by the greatest amount of seconds.The
4
afterCOUNT(DISTINCT...
is just the number of users in your criteria minus one (since user's are prevented from joining onto themselves). Adjust accordingly.What we should be returned with is the start and end time of the meeting in which all users can attend.
Query Breakdown
Given the following data:
The relative time interval positions should look like the following textual illustration (will have to sidescroll to see it all):
The numbers in between the brackets
[
]
represent the time window in which all users' free-times overlap. We want overlap #1 since it is the longest. Overlap #1 should be2012-07-18 1:10:00
to2012-07-18 2:00:00
, so our expected result should be:Step 1:
The first thing we must do is figure out what the end-times are of all potential meeting windows. We do this by selecting those particular intervals in which their end-times are in between all other users' free-time intervals.
The end-times returned represent the end-times of each overlap pointed out in the textual illustration above. If there are two of the same end-times returned, we only pick one since we don't need to know anything else about that end-time other than the fact that it is the latest time that that particular meeting can go until:
Renders:
SQLFiddle Demo
Step 2:
The next thing we will have to do is take the reverse of the last step and figure out all of the start-times of each potential meeting window, and join the result of this query with the result of the previous step on the condition that the start time is less than the previous step's end-time:
Renders:
The most recent
FromDateTimes
represent the start of each potential meeting window. We only want to pull the rows whereFromDateTime
is most recent perToDateTime
. We do this in the next step usingGROUP BY
in conjunction with theMAX()
aggregate function.SQLFiddle Demo
Step 3:
Next, we use
GROUP BY
onToDateTime
andMAX()
onFromDateTime
to pull only the most recentFromDateTimes
:Renders:
These are basically our potential time-windows. Now it's just a simple matter of selecting the longest one.
Step 4:
We use the
ORDER BY
/LIMIT 1
max/min selection technique since we only need one row. We order based on the seconds-difference between the end-time and start-time of each meeting, then select the one with the greatest amount of seconds (viaLIMIT 1
), giving us our final desired result:SQLFiddle Demo of Final Result
SQLFiddle Demo with Other Example Data
Getting the meeting time between all users in the table (no criteria):
If you don't want to specify which users you want to check meeting-times for (just do it for all users in the table), you can use:
Using sel's schema from the fiddle (10x sel)...
The simplest way too do this is:
Change according to your situation:
In my example we have 4 participants. n=4, participants (2,3,4,5)
IN (3,4,5) --> last n-1 id's of participants to the meeting
WHERE u1.userid=2 --> id for the first participant to the meeting
HAVING COUNT(DISTINCT u2.userid) = 3 --> n - 1
Can be tested on sqlfiddle
I created a 1D line-segment intersection algorithm in PHP utilizing a sweep line (Wikipedia). It works because datetimes can be mapped to a number-line: for example using "milliseconds since epoch".
See the implementation here: http://pastebin.com/iLwJQEF0
The algorithm outputs an array of line-segment intersections (which are also line-segments) that also have a list of all the users available for the duration. You can sort the intersections by your definition of "best" (and reverse it for descending): first by the number of available users and then by their durations. (Already implemented!)
It runs in
O(n * log n)
, wheren
is the number of time-periods.Notes: