Run CMD
Run CMD

Reputation: 3035

Calculating total night time from timespan

Suppose night time is set from 20.30h till 6.15h(AM). These 2 parameters are user-scoped variables. Suppose you have an arrival date and a departure date which can span from a few minutes to more than one total day. How do you calculate the total hours of night time?

public static double CalculateTotalNightTimeHours(DateTime arrival, 
                                                  DateTime departure,
                                                  int nightTimeStartHour, 
                                                  int nightTimeStartMinute, 
                                                  int nightTimeEndHour, 
                                                  int nightTimeEndMinute)
{ 
    //??
}

EDIT: I understand this may be no straight forward yes/no answer, but maybe someone has an elegant solution for this problem. To answer the comments : I indeed want to calculate the total number of hours (or minutes) that fall between a user-editable night start and end time. I'm calculating visit time, and the first date is indeed the arrival parameter.

The code I had sofar :

DateTime nightStart = new DateTime( departure.Year, departure.Month, departure.Day,
                                    nightTimeStartHour, nightTimeStartMinute, 0);
DateTime nightEnd = new DateTime( arrival.Year, arrival.Month, arrival.Day,
                                  nightTimeEndHour, nightTimeEndMinute, 0);
if (arrival < nightEnd)
{
    decimal totalHoursNight = (decimal)nightEnd.Subtract(arrival).TotalHours;
}
//...

Upvotes: 2

Views: 2497

Answers (2)

musefan
musefan

Reputation: 48415

Just because I was up for the challenge you should be able to use the following function with success. Please note that this is probably not the most efficient way to do it, but I did it this way so I could lay out the logic. I may decide to edit this as some point to improve it, but it should work fine as is.

It is also important to note a couple of assumptions here:

  1. the 'end' parameter is always greater than the 'start' parameter (although we check that first thing anyway)
  2. the night end parameters are earlier than the night start parameters (i.e. night time ends on the following day, but never as much as 24 hours later)
  3. Daylight savings time does not exist! (this is a tricky concern, one important question to address is: if either your start or end time is at 01:30 on the day the clocks go back, how will you know if the time was recorded before or after the rollback? i.e is it the first or second time the clock has hit 01:30?)

with that in mind...

public static double Calc(DateTime start, DateTime end, int startHour, int startMin, int endHour, int endMin)
{
    if (start > end)
        throw new Exception();//or whatever you want to do

    //create timespans for night hours
    TimeSpan nightStart = new TimeSpan(startHour, startMin, 0);
    TimeSpan nightEnd = new TimeSpan(endHour, endMin, 0);

    //check to see if any overlapping actually happens
    if (start.Date == end.Date && start.TimeOfDay >= nightEnd && end.TimeOfDay <= nightStart)
    {
        //no overlapping occurs so return 0
        return 0;
    }

    //check if same day as will process this differently
    if (start.Date == end.Date)
    {
        if (start.TimeOfDay > nightStart || end.TimeOfDay < nightEnd)
        {
            return (end - start).TotalHours;
        }

        double total = 0;
        if (start.TimeOfDay < nightEnd)
        {
            total += (nightEnd - start.TimeOfDay).TotalHours;
        }
        if(end.TimeOfDay > nightStart)
        {
            total += (end.TimeOfDay - nightStart).TotalHours;
        }
        return total;
    }
    else//spans multiple days
    {
        double total = 0;

        //add up first day
        if (start.TimeOfDay < nightEnd)
        {
            total += (nightEnd - start.TimeOfDay).TotalHours;
        }
        if (start.TimeOfDay < nightStart)
        {
            total += ((new TimeSpan(24, 0, 0)) - nightStart).TotalHours;
        }
        else
        {
            total += ((new TimeSpan(24, 0, 0)) - start.TimeOfDay).TotalHours;
        }

        //add up the last day
        if (end.TimeOfDay > nightStart)
        {
            total += (end.TimeOfDay - nightStart).TotalHours;
        }
        if (end.TimeOfDay > nightEnd)
        {
            total += nightEnd.TotalHours;
        }
        else
        {
            total += end.TimeOfDay.TotalHours;
        }

        //add up any full days
        int numberOfFullDays = (end - start).Days;
        if (end.TimeOfDay > start.TimeOfDay)
        {
            numberOfFullDays--;
        }
        if (numberOfFullDays > 0)
        {
            double hoursInFullDay = ((new TimeSpan(24, 0, 0)) - nightStart).TotalHours + nightEnd.TotalHours;
            total += hoursInFullDay * numberOfFullDays;
        }

        return total;
    }
}

You can then call it something like this:

double result = Calc(startDateTime, endDateTime, 20, 30, 6, 15);

Upvotes: 5

juharr
juharr

Reputation: 32276

Basically you'll want to calculate when night starts and ends. Then compare those to the arrival and departure dates to see if you arrival after night starts or depart before it ends to get the values you need to subtract to determine the total night hours. Then you need to continue to calculate this for each day until the start time for night is pass the departure date. Here's my solution for that.

public static double CalculateTotalNightTimeHours(
    DateTime arrival,
    DateTime departure,
    int nightTimeStartHour,
    int nightTimeStartMinute,
    int nightTimeEndHour,
    int nightTimeEndMinute)
{
    if (arrival >= departure)
        return 0;

    var nightStart = arrival.Date.AddHours(nightTimeStartHour).AddMinutes(nightTimeStartMinute);
    var nightEnd = nightStart.Date.AddDays(1).AddHours(nightTimeEndHour).AddMinutes(nightTimeEndMinute);

    double nightHours = 0;
    while (departure > nightStart)
    {
        if (nightStart < arrival)
            nightStart = arrival;
        if (departure < nightEnd)
            nightEnd = departure;
        nightHours += (nightEnd - nightStart).TotalHours;
        nightStart = nightStart.Date.AddDays(1).AddHours(nightTimeStartHour).AddMinutes(nightTimeStartMinute);
        nightEnd = nightStart.Date.AddDays(1).AddHours(nightTimeEndHour).AddMinutes(nightTimeEndMinute);
    }

    return nightHours;
}

You'd probably also want to add checking to make sure the start and end hours are within range. This also assumes that night starts on one day and ends on the next, so if you wanted night to end before midnight you'd have to do something else.

Upvotes: 3

Related Questions