1
\$\begingroup\$

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)
            end = end.AddDays(1);

        TimeSpan duration = end.Subtract(start);

        return duration.TotalHours;
    }
\$\endgroup\$
1
  • \$\begingroup\$ Can you post the class that variable monday was created with? \$\endgroup\$ – Rick Davin Jun 2 '20 at 20:36
1
\$\begingroup\$

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.

\$\endgroup\$
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.