# Working out how many hours worked after a certain time

I am working on some custom rules in a time managment system and need to know how many hours in a shift have been before a certain time (19:00pm) and how many hours after. Shifts can start in the evening and finish in the morning so need to take that into account.

So far I have the below (this is just a snippet for one day) however it seems very clumsy and eloborate what I have written, can't help but feel I am missing a simpler solution, anyone have any ideas?

    DateTime cutOffTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 19, 00, 00);
string cutOffTimeOfDay = GetTimeOfDayFromDateTime(cutOffTime);

double baseMondayHours = 10.00;
baseMondayHours = (baseMondayHours - 0.5);

if (GetTimeOfDayOnlyFromDateTime(monday.ShiftStart.Value) == "AM" && GetTimeOfDayOnlyFromDateTime(monday.ShiftEnd.Value) == "PM"
&& monday.ShiftEnd.Value.TimeOfDay < cutOffTime.TimeOfDay)
{
postCutOffMondayHours = 0;
baseMondayHours = monday.HoursWorked.Value;
}
else
{
string endTimeOfDay = GetTimeOfDayFromDateTime(monday.ShiftEnd.Value);
double hoursAfterCutOff = GetDuration(cutOffTimeOfDay, endTimeOfDay);

postCutOffMondayHours = hoursAfterCutOff;
baseMondayHours = (baseMondayHours - hoursAfterCutOff);
}

public static string GetTimeOfDayFromDateTime(DateTime d)
{
return d.ToString("HH:mm") + " " + d.ToString("tt", CultureInfo.InvariantCulture);
}

public static string GetTimeOfDayOnlyFromDateTime(DateTime d)
{
return d.ToString("tt", CultureInfo.InvariantCulture).ToUpper();
}

public static double GetDuration(string startTime, string endTime)
{
DateTime start = DateTime.Parse(startTime);
DateTime end = DateTime.Parse(endTime);
if (start > end)

TimeSpan duration = end.Subtract(start);

return duration.TotalHours;
}

• Can you post the class that variable monday was created with? – Rick Davin Jun 2 '20 at 20:36

I agree with your summation that it is clumsy. I see you like to stringly type objects, such as GetTimeOfDayFromDateTime. It would be neater to just get the time of day as a TimeSpan. Also, you may have several overloads accepting different input arguments, so you don't need to include the FromDateTime in the name.

public static TimeSpan GetTimeOfDay(DateTime d) => d - d.Date;


Or if you want to simply check AM versus PM, you could use the DateTime.Hour. If the hour is < 12, it's AM. Otherwise, it's PM.

Now GetDuration doesn't have to accept string inputs. They can accept the TimeSpan (i.e. time of day) for start and end, or just better yet, just subtract the 2 DateTime objects.

This just looks clumsy:

double baseMondayHours = 10.00;
baseMondayHours = (baseMondayHours - 0.5);


Cleaner would be either:

double baseMondayHours = 10.0 - 0.5;


or directly

double baseMondayHours = 9.5;


Another tip to keep in mind: Subtracting dates can produce bad results if the Kind of each DateTime is different. Doesn't seem to be the case here, but be forewarned.