Aggregate 15 minute time slots to 30 minutes time slots - asp.net-mvc

I have a list of time slots with a 15 minute interval.
Each slot can have a activity bound to it that makes the slot "reserved".
What is the best way to return the slots in groups of 30 minutes.
So basically, how can I go from this:
10:00
10:15 = this is a reserved slot
10:30
To this:
10:00
10:30
This whole slot is then reserved because it contains the reserved 10:15 slot.
Without changing the slot size itself.
Is this possible to do within the linq query itself or do I have to return the collection of 15 minute slots and apply the 30 minute logic afterwards?
Please point me in the right direction, thanks!
The slots are object with these properties and types:
TimeslotId (int)
SlotStart (DateTime)
ActivityId (int)
UPDATE:
Ok, I tried to group the slots with this query.
var groups = service.TestGrouping().GroupBy(x =>
{
var stamp = x.SlotStart;
stamp = stamp.AddMinutes(-(stamp.Minute % 30));
stamp = stamp.AddMilliseconds(-stamp.Millisecond - 1000 * stamp.Second);
return stamp;
}).Select(g => new Sample() { GroupTime = g.Key, GroupedSlots = g.ToList() }).ToList();
Which takes me a little closer. Now I get the slots aggregated to closest 30 minute, like 8:00-8:30, 8:30-9:00.
However, this does not work for slots that is within quarter to / quarter past. I need some logic to catch all possible half hours:
8:00-8:30, 8:15-8:45, 8:30-9:00, 8:45-9:15.
How would the logic look like?

Related

Time function in sheets

I have the data of 4000 employees in google sheets along with their shift timings (9 hour long shift) spread across 24 hours. I wish to use a formula to understand the most common timing these employees are available in the office (09:00 to 18:00). My results would be 09:00 to 11:00, 11:00 to 13:00, 13:00 to 15:00, 15:00 to 18:00, 18:00 to 22:00, 22:00 to 09:00.
I could have used this formula to derive to the value:
=IF(AND(TIMEVALUE(A2)>=TIMEVALUE("09:00"), TIMEVALUE(A2)<=TIMEVALUE("11:00")), "09:00 to 11:00",
IF(AND(TIMEVALUE(A2)>=TIMEVALUE("11:00"), TIMEVALUE(A2)<=TIMEVALUE("13:00")), "11:00 to 13:00",
IF(AND(TIMEVALUE(A2)>=TIMEVALUE("13:00"), TIMEVALUE(A2)<=TIMEVALUE("15:00")), "13:00 to 15:00",
IF(AND(TIMEVALUE(A2)>=TIMEVALUE("15:00"), TIMEVALUE(A2)<=TIMEVALUE("18:00")), "15:00 to 18:00",
IF(AND(TIMEVALUE(A2)>=TIMEVALUE("18:00"), TIMEVALUE(A2)<=TIMEVALUE("22:00")), "18:00 to 22:00", "22:00 to 09:00")))))
but the problem is the timings are not in the time format but they are in text format
Here's my take:
Suppose Column A has clock ins, and Column B has clock outs. Let Column D have Times starting at 00:00 and going up to 33:00 (8am next day) in 5 minute (or 30, 60 etc) increments.
Let column E be the amount of clock in and outs that an employee was in the office at the time referred to in E.
We will define E to be =COUNTIFS($A$2:$A$9999,"<="&D2,$B$2:$B$9999,">="&D2).
Next, apply some conditional formatting to highlight the most busy times.
Note that you will need only the times of day, which it sounds like you have, but you will need to convert overnight shifts to not wrap around midnight.

How to More Elegantly Calculate Epoch Time for Next Sunday at Midnight in Dart?

When a user opens my app, there's a countdown timer that shows how much time left until Sunday at midnight (which is when the week's contest would end).
To get the initial value used in the countdown, my code adds 604800000 (which is the amount of milliseconds in a week) in a loop to a starting value of 1595203200000 (which the milliseconds since epoch of an arbitrary past Sunday at midnight) until it's greater than now:
int now = DateTime.now().millisecondsSinceEpoch;
int nextSundayAtMidnight = 1595203200000; // starting value is from arbitrary past Sunday at midnight
while (now > nextSundayAtMidnight) {
print('now is still greater than nextSundayAtMidnight so adding another 604800000 until it\'s not');
nextSundayAtMidnight += 604800000;
}
print('nextSundayAtMidnight is $nextSundayAtMidnight');
It works, but it seems like there should be a better way that's based on DateTime.now without having to manually specify that arbitrary starting value. Is there?
What's the syntax in dart to do this more elegantly?
Thanks in advance!
The following code uses addition of the difference in weekdays to get the date of the upcoming Sunday and then shifts the exact DateTime to being at 11:59:59 pm. There are comments in the code that describe what each line does.
It uses the many helpful methods already provided in the DateTime class in dart.
void main()
{
var now = DateTime.now();
//Obtains a time on the date of next sunday
var nextSunday = now.add(Duration(days: DateTime.sunday - now.weekday));
//Shifts the time to being 11:59:59 pm on that sunday
var nextSundayMidnight = DateTime(nextSunday.year, nextSunday.month, nextSunday.day + 1).subtract(Duration(seconds: 1));
//Gets the difference in the time of sunday at midnight and now
var timeToSundayMidnight = nextSundayMidnight.difference(now);
print(timeToSundayMidnight);
}

Dart: inconsistency in adding days to dates

When adding one day to 2020-09-18 I get 2020-09-19 00:00:00.000 but when I add 3 days (or more) I get 2020-09-20 23:00:00.000 which first why I got 23 hour? second adding 3 days to 18 is 21 not 20!
What is the problem?
void main() {
var dateOne = DateTime.parse('2020-09-18 00:00:00.000');
var dateTwo = dateOne.add(Duration(days: 1 )); // 2020-09-19 00:00:00.000
var dateThree = dateOne.add(Duration(days: 3 )); // 2020-09-20 23:00:00.000
print(dateTwo);
print(dateThree);
}
The reason for this is Daylight Saving Time since the add method does only understand seconds as documented in the API and the Duration are therefore converted to seconds before it is used:
Notice that the duration being added is actually 50 * 24 * 60 * 60 seconds. If the resulting DateTime has a different daylight saving offset than this, then the result won't have the same time-of-day as this, and may not even hit the calendar date 50 days later.
Be careful when working with dates in local time.
https://api.dart.dev/stable/2.7.2/dart-core/DateTime/add.html
As you also have mentioned yourself, you can get around the issue by using UTC instead.

Googl Sheets - Time Range to Table

I want to take a time range and convert it to minutes within a table of 30 minute segments. For example, Bob works from 3:35 AM to 5:00 AM. So within the table from 3:30 AM - 4:00 AM should represent 25 minutes, because Bob was working a total of 25 minutes during that time slot. Then the time slots for 4:00 - 4:30 AM and 4:30 - 5:00 AM would both have 30 in their corresponding cells.
Apologies to leave this so broad but I honestly have no idea where to start and this forum has been immensely helpful.
https://docs.google.com/spreadsheets/d/1YpHU-UHlqXL6c8I27zSDZaRu72ViUw5W6RPru-HE3Iw/edit#gid=0
Any help is appreciated.
For each 30-minute interval, you have to check whether these two conditions are met:
The interval start time (3:30) falls between the employee start and end time (3:35 and 5:00).
The interval end time (4:00) falls between the employee start and end time.
If any of these conditions are met, the working time for that interval won't be 0. The working time will be the difference between the minimum of both end times (4:00 and 5:00) and the maximum of both start times (3:30 and 3:35).
Translated to sheets functions, you could do something like this:
=IF(MIN($D2,O$1)-MAX($C2,N$1)>0,TIMEVALUE(MIN($D2,O$1)-MAX($C2,N$1))*24*60,0)
Or, alternatively, this:
=IF(OR(AND($C2<N$1,N$1<$D2),AND($C2<O$1,O$1<$D2)),TIMEVALUE(MIN($D2,O$1)-MAX($C2,N$1))*24*60,0)

Appointment Scheduling in ruby/rails

I am working on a call center software in rails and need to schedule appointments for agents that can handle calls for the customers. Having said the call center software, need to make sure that I schedule the appointments utilizing the entire agent's schedule as much as possible, leaving scope for least number of holes (where agent has no appointment).
Given an agent's schedule, for example 9:00AM to 5:30PM for a given day, with a lunch break of 30 minutes between 1:00PM - 1:30PM, I need to schedule appointments of varying length in duration, some 60 minutes and some 90 minutes.
And if some reason, lunch break is leaving some holes in the schedule, I should be able to move lunch break 30minutes +/-, so instead of 1:00PM - 1:30PM it could be moved between 1:30PM - 2:00PM or 12:30PM - 1:00PM.
I started off creating lunch breaks as a kind of appointment which will provide the flexibility of moving the starts_at and finishes_at attributes. And the appointments being either 60 minutes or 90 minutes, which are multiple of 30 minutes and lunch also being 30 minutes, I started off splitting agents schedule into slots of 30 minutes each.
So for a given agent on a given day, looking at his schedule I instantiated an array of slots each with a duration of 30 minutes and starts_at and finishes_at attributes be like 9:00AM - 9:30AM, 9:30AM - 10:00AM, etc.
I need some help on looping through this array of appointment slots and pull either 2 consecutive slots or 3 consecutive slots depending upon 60 or 90 minute duration appointment, keeping in mind that I should be able to move the lunch +/- 30 minutes.
Any help is much appreciated.
Looking at your problem:
Appointments are either 60 or 90 minutes long.
Lunch can vary between a 90 minute interval 12:30-2:00
And we want to minimize the amount of minutes that have no appointments.
Now, you have a time interval to fill, which is 9:00AM to 5:30pm. Assuming appointments fall between 9:00-5:30, we can use a greedy algorithm for interval scheduling based on earliest finish time (source) with your additional constraint.
Basically the algorithm is as follows (in pseudo)
Let R be the set of all appointments
Let R11 be the set of appointments from R before 12:30 that are compatible with 12:30-1:00 and R12 be the set of appointments from R after 1:00 that are compatible with 12:30-1:00
Let R21 be the set of appointments from R before 1:00 that are compatible with 1:00-1:30 and R22 be the set of appointments from R after 1:30 that are compatible with 1:00-1:30
Let R31 be the set of appointments from R before 1:30 that are compatible with 1:30-2:00 and R32 be the set of appointments from R after 2:00 that are compatible with 1:30-2:00
Let R1Comb = findSet(R11) + 12:30-1:00 + findSet(R12)
Let R2Comb = findSet(R21) + 1:00-1:30 + findSet(R22)
Let R3Comb = findSet(R31) + 1:30-2:00 + findSet(R32)
Function findSet(R)
Let A be the time interval to fill
While R is not empty
Choose a request r in R that has the smallest finishes_at
Add r to A
Remove all appointments in R that are not compatible with r
EndWhile
Return A
EndFunction
Return the R that has the smallest amount of holes in R1Comb, R2Comb, R3Comb
This algorithm makes use of a few concepts
An appointment r1 is not compatible with r2 if they overlap.
Because of #1, we know that Ri1/Ri2 for i=1,2,3 will not be conflicting with each other. Because if an appointment in Ri2 is not compatible with Ri1, then it is also not compatible with the lunch period, which is a contradiction because we took out all the non compatible appointments.
Once we split the set of appointments, then it's a matter of solving 2 scheduling problems, which can be solved greedily.
An this algorithm is still O(n log n) because you are doing the greedy algorithm 6 times (a constant), and each greedy iteration is O(n log n), and the first few lines and the last line are all O(n).
People write theses on scheduling and it's not an easy problem. I suggest you looking at http://www.asap.cs.nott.ac.uk/watt/resources/university.html to get a better understanding.
Good luck :)

Resources