Find timestamp closest to one hour ago in a list - c#

So I have a list of timestamps, they're not uniformly spaced meaning one time stamp can be 10 minutes after the previous or 5 seconds after. What's the best way to find the index of the entry that is closest to (DateTime.Now.TotalSeconds - 3600)?

Since you don't gave any specific code, we can only do suggestions on that.
What you can do, is take the absolute difference of the date in the list and compare that to the desired date, taking the lowest.
Something like:
list.OrderBy( x => Math.Abs((x.Date - desiredDate).TotalMilliseconds)).FirstOrDefault();

Related

In C#, what would a Timespan.FromSeconds(-1) mean when used in a comparison?

Some code I was reading recently did a time calculation something like:
if (TimeWhenResponseArrived - TimeWhenRequested > Timespan.FromSeconds(-1))
I am having a hard time understanding what is trying to be done here. Are they subtracting the times and basically trying to see if they are less than 1 second apart?
Subtracting one DateTime variable from another one will return you a TimeSpan typed result. The code compares the result to decide if the difference is more than a second.

Getting random numbers after a simple math problem. Might be a local variable thing

I have a GUI working on the front end. But on the back end I have a little problem with my math. Code is trying to calculate how much time has gone with only starting and ending hours. (There are no info on days). So I think I found the way to calculate the hours spent on paper. But in C# I failed I think because of local variable stuff.
float start = float.Parse(textBox1.Text);
float end = float.Parse(textBox2.Text);
float hours_spent = end - start;
if (start > end) {
hours_spent = 24.00f -start + end;
}
First part is working correctly but when I give the start bigger than end, it gives me random numbers.
EDIT: When i gave 14.00 as an input and 13.00 as an output i get -76
and for input 14.00 output 12.00 i get -176 and for 18.50 to 10.25 i get -801. It is not random i can see that too my bad on choosing the words. But i dont get it what is wrong
When i gave 14.00 as an input and 13.00 as an output i get -76
You are parsing in a part of the world where . is not the decimal separator but is a common "group" separator. That is, a number like one hundred thousand plus a quarter is written 100.000,25, and not as it would be in the United States, 100,000.25. Parse assumes that the string is in the format of the current user's locale unless you tell it otherwise.
Therefore you are parsing the strings into values 1400 and 1300. Their difference is -100, which is less than 0, so you add 24 to -100 and get -76.
Same for your other case. You have 1850 and to 1025, subtract them to get -825, add 24 and you get -801.
There's nothing "random" at all here; everything is working as expected.
There is a lesson here: work backwards. You got -76. How'd that happen? You must have added 24 to something. What added to 24 gives you -76? -100. How did we get -100? And so on.
Start over. You should not be parsing floats in the first place. If this is a decimal quantity then you should be parsing a decimal, and if you know that it will always have . as the decimal separator, you should say so when you parse it. (Hint: use the version of TryParse that takes a NumberStyles and set the style correctly.)
If, on the other hand, you know that this is two integers separated by a period, then you should not be parsing it as a decimal or a float. You should be parsing an integer, then a period, then an integer.
If this is hours then a period then minutes, then again, you should not be using any of the above. Use a date and time parser to parse dates and times.
In short: use the right tool for the job you actually have to do.
Other problems with your code:
Use TryParse, not Parse, when dealing with user input. You don't know that there is a valid number in there, but Parse will crash if it gets bad input.
Your math is probably wrong. If someone puts in 100 and 200, do you really want -76 as the output?
Take a step back and ask yourself what the real business process is that you're trying to build here. Write that business process down carefully and then implement that process, not an approximation of it. Your business process probably does not say "parse a float using the rules of the current locale" but that's the code you wrote. Write code that means exactly what you intend it to mean.
UPDATE: Comments on the question indicate just how deep a hole you've gotten yourself into:
If entry time is 13.55 and exit time is 14.05 what should be the expected logical result ? It should be 10 (minutes) or 50 (numeric difference) ?
I am expecting 10 as minutes
Then absolutely you should not be parsing as float or decimal! Parsing as float or decimal is obviously completely wrong because 1.1 and 1.10 are the same value as a number, but nine minutes different if it is "hours.minutes", and you can't tell which case you are in by parsing as a number.
Again, you need to stop writing code, erase everything you've written so far, and start over. You're in a hole: stop digging deeper, fill in the hole, and get back to ground level.
You need to figure out exactly what format your strings are in, and parse exactly that format and nothing else.
So, write a specification that poses and then answers questions about what is allowed and what is not. Are negative values allowed? What if the number of minutes is more than 60? What if the minutes or hours are missing entirely? And so on.
Once you have a specification, write test cases that verify the spec. Then write an implementation, and run your tests. The code is more likely to be correct if you write the tests first.
I'm going to completely ignore providing a didactic answer in favor of trying to sidestep the problem.
Avoid writing your own parsing code. Instead, replace all your TextBoxes with DateTimePickers with Format set to Time. Then pull out the time by calling the .Value.TimeOfDay property. TimeOfDay is a TimeSpan, so it supports simple arithmetic.
Warning: Watch out when pulling these results using the provided properties. For example, 150 minutes can be translated as either 2 .Hours and 30 .Minutes or to 150 .TotalMinutes .

Generate closest teams based on employee schedules C#

I am given a csv of employee schedules with columns:
employee ID, first last name, sunday schedule, monday schedule, ... , saturday schedule
1 week schedule for each employee. I've attached a screenshot of a portion of the csv file. The total file has around 300 rows.
I need to generate teams of 15 based on the employees' schedules (locations don't matter) so that the employees on each team have the closest schedules to each other. Pseudocode of what I have tried:
parse csv file into array of schedules (my own struct definition)
match employees who have the same exact schedule into teams (creates ~5 full sized teams, 20 - 25 half filled teams, leaves ~50 schedules who don't match with anyone)
for i = 1 to 14, for each member of teams of size i, find the team with the closest schedule (as a whole) and add the member to that team. Once a team reaches size 15, mark them as "done".
This worked somewhat but definitely did not give me the best teams. My question is does anyone know a better way to do this? Pseudocode or just a general idea will help, thanks.
EDIT: Here is an example of the formula of comparison
The comparison is based on half hour blocks of difference between the agents schedules. Agent 25 has a score of 16 because he has a difference of 8 half hours with Agent 23 and 24. The team's total score is 32 based on everyone's scores added together.
Not all agents work 8 hour days, and many have different days off, which have the greatest effect on their "closeness" score. Also, a few agents have a different schedule on a certain day than their normal schedule. For example, one agent might work 7am - 3pm on mondays but work 8am - 4pm on tuesday - friday.
Unless you find a method that gets you an exact best answer, I would add a hill-climbing phase at the end that repeatedly checks to see if swapping any pair of agents between teams would improve things, and swaps them if this is the case, only stopping when it has rechecked every pair of agents and there are no more improvements to be made.
I would do this for two reasons:
1) Such hill-climbing finds reasonably good solutions surprisingly often.
2) People are good at finding improvements like this. If you produce a computer-generated schedule and people can find simple improvements (perhaps because they notice they are often scheduled at the same time as somebody from another team) then you're going to look silly.
Thinking about (2) another way to find local improvements would be to look for cases where a small number of people from different teams are scheduled at the same time and see if you can swap them all onto the same team.
Can't say for sure about the schedules, but in string algorithms you can find an edit distance calculation. The idea is to define number of operations you need to perform to get one string from another. For example, distance between kitten and sitting is 3, 2 for substitutions and 1 for deletion. I think that you can define a metric between two employees' schedule in similar way.
Now, after you have a distance function, you may start a clusterization. The k-means algorithm may be a good start for you, but it's main disadvantage is that the number of groups is fixed initially. But I think that you can easily adjust general logic for your needs. After that, you may try some additional ways to cluster your data, but you really should start with your distance function, and then simply optimize it on your employee records.

How to disable the booked time slots from a list of business hour time slots

Friends,
I' working Appointment booking Project, Details are as follows:
Business hour starts from 9:00 to 7:00 with default duration of 30mins. So, Slots start like (9:00, 9:30, 10:00.... 7:00).
Here, to show the available slots, I'm using the following Logic.
Storing all the Slots with 30 min duration in a list (LIST A) like [9:00, 9:30, 10:00, 10:30, ... 7:00]
Looping through booked appointments (contains start and end time), and if start time is matched with any of LIST A elements, I', removing that element from that List. and Loop continues.
Here, the problem is, Consider If appointment is booked 9:30-10:00.
Based on my logic, 9:30 is matched with LIST A element, and It will remove 9:30 from that list.
So, available slots will be displayed as [9:00, X ,10:00, 10:30, .... 7:00]. Actually It should be [9:00, 9:30, 10:30, 11:00... 7:00]
Instead of showing available slots 9:00-9:30, 10:30-11:00 it shows 9:00-10:00, 10:30-11 since 9:30 is removed from the list.,
Please help to solve this, or suggest me some alternative approaches for this problem. Badly needed.
The thing you are mixing up is, you are taking second slot's start time as first slot's end time. So rather then doing that, what you can do is to store start time and duration.
And to simply compute the end time, you do
StartTime.AddMinutes(30);
And to add one more comment at end; you are trying to build a very rigid structure. And will face problems if you'd try to extend the application, IMHO.
I suggest, Instead of using Single Dimensional Array, use Multidimensional array like
[[9:00][9:30],[9:30][10:00],[10:00][10:30], .... nth Item]
Here, Logic should be like this
var start=[start time]
var end=[end time]
var duration=[duration]
for (i=start;i<end;i+=duration)
{
if(start==A[i][0])
remove(A[i][0]);
}
A.sort();
return A;

LINQ Query - nearest adjacent date

I am trying to write a method that will determine the closest date chronlogically, given a list of dates and a target date. For example, given a (simplified) date set of {Jan 2011, March 2011, November 2011}, and a target date of April 2011, the method would return March 2011
At first, I was thinking of using LINQ's skip, but I'm not sure of an appropriate Func such that it would stop before the date was exceeded. This below seems a viable solution, but I'm not sure if there's a more efficient means of doing this. Presumably Last and First would be linear time each.
The source dataSet can be between 0 and 10,000 dates, generally around 5,000. Also, I am iterating over this whole process between 5 and 50 times (this is the number of target dates for different iterations).
// assume dateSet are ordered ascending in time.
public DateTime GetClosestDate(IEnumerable<DateTime> dateSet, DateTime targetDate)
{
var earlierDate = dateSet.Last(x => x <= targetDate);
var laterDate = dateSet.First(x => x >= targetDate);
// compare TimeSpans from earlier to target and later to target.
// return closestTime;
}
Well, using MinBy from MoreLINQ:
var nearest = dateSet.MinBy(date => Math.Abs((date - targetDate).Ticks);
In other words, for each date, find out how far it is by subtracting one date from the other (either way round), taking the number of Ticks in the resulting TimeSpan, and finding the absolute value. Pick the date which gives the smallest result for that difference.
If you can't use MoreLINQ, you could either write something similar yourself, or do it in two steps (blech):
var nearestDiff = dateSet.Min(date => Math.Abs((date - targetDate).Ticks));
var nearest = dateSet.Where(date => Math.Abs((date - targetDate).Ticks) == nearestDiff).First();
Using Last and First iterates the dateSet twice. You could iterate the dateSet yourself using your own logic. This would be more efficient, but unless your dateSet is very large or enumerating the dateSet is very costly for some other reason, the little gain in speed is probably not worth writing a more complicated code. Your code should be easy to understand in the first place.
It is simple!
List<DateTime> MyDateTimeList =....;
....
getNearest(DateTime dt)
{
return MyDateTimeList.OrderBy(t=> Math.ABS((dt-t).TotalMiliSeconds)).First();
}

Categories

Resources