两天之间的CalculateTotalHours排除日期和时间范围

时间:2019-05-23 21:11:18

标签: c# date datetime math time

编辑:

如何计算两个日期之间的总时数(包括上午8点以后的星期一的小时,但不包括下午5点以后的星期五的小时)?并排除假期和周末(我已经对此有逻辑)。

我们要在星期一上午8点至星期五下午5点之后开始计时。

  • 星期一的全天工作时间是16。
  • 星期五的全天工作时间是17。
  • 星期一至星期五之间的每一天都是24小时。

示例:

// startDate = "May 19 2019 10PM" as DateTime // Sunday
// endDate = "May 21 2019 8AM" as DateTime // Tuesday

// Expected Output: 24 hr (Excludes all time before 8am on Monday)

-------------------------------------------------------

// startDate = "May 15 2019 5PM" as DateTime // Wednesday
// endDate = "May 18 2019 10AM" as DateTime // Saturday

// Expected Output: 48 hr (Excludes all time after 5PM on Friday)

public static double GetTotalHoursBetweenDays(DateTime startDate, DateTime endDate) 
{

}

1 个答案:

答案 0 :(得分:0)

使用我几年前写的BusinessDayCalculator,以下代码将使您获得DateTime对象之间的工作时间数。

void Main()
{
    // Setup the BusinessDayCalculator with the relevant holidays
    var bdCalc = new BusinessDayCalculator(
        new List<BusinessDayCalculator.Holiday> {
            BusinessDayCalculator.Holiday.NewYearsDay,
            BusinessDayCalculator.Holiday.MartinLutherKingDay,
            BusinessDayCalculator.Holiday.PresidentsDay,
            BusinessDayCalculator.Holiday.MemorialDay,
            BusinessDayCalculator.Holiday.IndependenceDay,
            BusinessDayCalculator.Holiday.LaborDay,
            BusinessDayCalculator.Holiday.VeteransDay,
            BusinessDayCalculator.Holiday.Thanksgiving,
            BusinessDayCalculator.Holiday.Christmas},
        false);

    // Your start and end days (spanning Memorial Day in 2010)
    var fromDate = new DateTime(2019, 5, 23, 17, 0, 0);
    var tillDate = new DateTime(2019, 5, 29, 13, 0 , 0);

    // Total business days (including the start and end dates)
    var businessDays = bdCalc.GetBusinessDaysBetweenDates(fromDate, tillDate);

    // Define your working hours
    var startOfBusinessHour = 8;
    var endOfBusinessHour = 17;

    // Calculate working hours on the first day
    var startHours = fromDate.Hour >= endOfBusinessHour ? 0 : fromDate.Hour - startOfBusinessHour;

    // Calculate working hours on the last day
    var endHours = tillDate.Hour >= endOfBusinessHour ? 0 : tillDate.Hour - startOfBusinessHour;

    // Calculate the total number of hours by 
    var hours = (businessDays > 2 ? (businessDays - 2) * (endOfBusinessHour - startOfBusinessHour) : 0) + startHours + endHours;

    Console.WriteLine($"There are {hours} working hours between {fromDate:g} and {tillDate:g}.");   
}

public static DateTime SetTime(DateTime date, Int32 hour)
{
    return new DateTime(date.Year, date.Month, date.Day, hour, 0, 0);
}

public class BusinessDayCalculator
{
    public enum Holiday { NewYearsEve, NewYearsDay, MartinLutherKingDay, PresidentsDay, Easter, MemorialDay, FlagDay, IndependenceDay, LaborDay, ColumbusDay, VeteransDay, Thanksgiving, DayAfterThanksgiving, Christmas };

    public List<Holiday> ObservedHolidays { get; private set; }

    public Boolean WeekendIncludesSaturday { get; private set; }

    public BusinessDayCalculator(List<Holiday> observedHolidays, bool weekendIncludesSaturday)
    {
        ObservedHolidays = observedHolidays;
        WeekendIncludesSaturday = weekendIncludesSaturday;
    }

    public DateTime AdjustForBusinessDay(DateTime date)
    {
        DateTime businessDay = new DateTime(date.Year, date.Month, date.Day);
        while (!IsBusinessDay(businessDay))
        {
            businessDay = businessDay.AddDays(1);
        }
        return businessDay;
    }

    public DateTime AddBusinessDays(DateTime startDate, Int32 businessDays)
    {
        DateTime endDate = startDate;

        int count = 0;
        while (Math.Abs(businessDays) > count)
        {
            endDate = endDate.AddDays(businessDays > 0 ? 1 : -1);
            if (IsBusinessDay(endDate))
            {
                count++;
            }
        }
        return endDate;
    }

    public Boolean IsBusinessDay(DateTime date)
    {
        return !IsWeekendDay(date) && !IsHoliday(date);
    }

    public Boolean IsWeekendDay(DateTime date)
    {
        return (WeekendIncludesSaturday && date.DayOfWeek == DayOfWeek.Saturday) || date.DayOfWeek == DayOfWeek.Sunday;
    }

    public Boolean IsHoliday(DateTime date)
    {
        return ObservedHolidays.Any(holiday => GetHoliday(holiday, date).DayOfYear == date.DayOfYear);
    }

    public DateTime GetHoliday(Holiday holiday, DateTime date)
    {
        switch (holiday)
        {
            case Holiday.NewYearsEve:
                // New year's eve always falls on the 31st of December
                return AdjustHolidayForWeekend(new DateTime(date.Year, 12, 31));
            case Holiday.NewYearsDay:
                // New year's day always falls on the 1st of January.
                return AdjustHolidayForWeekend(new DateTime(date.Year, 1, 1));
            case Holiday.MartinLutherKingDay:
                // Martin Luther King day is always observed on the 3rd Monday of January.
                return GetNthDayOfWeekOfMonth(date.Year, 1, 3, DayOfWeek.Monday);
            case Holiday.PresidentsDay:
                // Presidents day or Washingtons birthday is always observed on the 3rd Monday in February.
                return GetNthDayOfWeekOfMonth(date.Year, 2, 3, DayOfWeek.Monday);
            case Holiday.Easter:
                // We don't adjust this holiday since it's always observed on Sunday Source: http://www.smart.net/~mmontes/nature1876.html
                var a = date.Year % 19;
                var b = date.Year / 100;
                var c = date.Year % 100;
                var d = b / 4;
                var e = b % 4;
                var f = (b + 8) / 25;
                var g = (b - f + 1) / 3;
                var h = (19 * a + b - d - g + 15) % 30;
                var i = c / 4;
                var k = c % 4;
                var l = (32 + 2 * e + 2 * i - h - k) % 7;
                var m = (a + 11 * h + 22 * l) / 451;
                var p = (h + l - 7 * m + 114) % 31;
                var easterMonth = (h + l - 7 * m + 114) / 31;
                var easterDate = p + 1;
                return new DateTime(date.Year, easterMonth, easterDate);
            case Holiday.MemorialDay:
                // Memorial day is always on the last Monday in May
                return GetLastDayOfWeekOfMonth(date.Year, 5, DayOfWeek.Monday);
            case Holiday.FlagDay:
                // Flag day is always on the same day June 14th
                return AdjustHolidayForWeekend(new DateTime(date.Year, 6, 14));
            case Holiday.IndependenceDay:
                // Independence day or 4th of July is always on the same day July 4th
                return AdjustHolidayForWeekend(new DateTime(date.Year, 7, 4));
            case Holiday.LaborDay:
                // Labor day is always on the 1st Monday in September
                return GetNthDayOfWeekOfMonth(date.Year, 9, 1, DayOfWeek.Monday);
            case Holiday.ColumbusDay:
                // Columbus day is always on the 2nd Monday of October
                return GetNthDayOfWeekOfMonth(date.Year, 10, 2, DayOfWeek.Monday);
            case Holiday.VeteransDay:
                // Veterans day is always on the same day November 11th
                return AdjustHolidayForWeekend(new DateTime(date.Year, 11, 11));
            case Holiday.Thanksgiving:
                // Thanksgiving is always on the 3rd Thurday in November
                return GetNthDayOfWeekOfMonth(date.Year, 11, 4, DayOfWeek.Thursday);
            case Holiday.DayAfterThanksgiving:
                // Day After Thanksgiving is always on the 3rd Friday in November (Black Friday)
                return GetHoliday(Holiday.Thanksgiving, date).AddDays(1);
            case Holiday.Christmas:
                // Christmas is always on the same day December 25th
                return AdjustHolidayForWeekend(new DateTime(date.Year, 12, 25));
            default:
                throw new ArgumentException("Unknown Holiday");
        }
    }

    protected DateTime GetNthDayOfWeekOfMonth(Int32 year, Int32 month, Int32 week, DayOfWeek dayOfWeek)
    {
        DateTime date = new DateTime(year, month, 1);
        while (date.DayOfWeek != dayOfWeek)
        {
            date = date.AddDays(1);
        }

        if (week > 1)
        {
            return date.AddDays(7 * (week - 1));
        }
        return date;

    }

    protected DateTime GetLastDayOfWeekOfMonth(Int32 year, Int32 month, DayOfWeek dayOfWeek)
    {
        DateTime date = new DateTime(year, month, DateTime.DaysInMonth(year, month));
        while (date.DayOfWeek != dayOfWeek)
        {
            date = date.AddDays(-1);
        }
        return date;
    }

    protected DateTime AdjustHolidayForWeekend(DateTime holiday)
    {
        // Falls on Saturday, observed on Friday
        if (WeekendIncludesSaturday && holiday.DayOfWeek == DayOfWeek.Saturday)
        {
            return holiday.AddDays(-1);
        }

        // Falls on Sunday, observed on Monday
        if (holiday.DayOfWeek == DayOfWeek.Sunday)
        {
            return holiday.AddDays(1);
        }
        return holiday;
    }


    public Int32 GetBusinessDaysBetweenDates(DateTime startDate, DateTime endDate)
    {
        DateTime adjustedStartDate = startDate;

        if (endDate < adjustedStartDate)
        {
            throw new Exception("end date before start date");
        }

        int count = 0;
        while (adjustedStartDate < endDate)
        {
            adjustedStartDate = adjustedStartDate.AddDays(1);
            if (IsBusinessDay(adjustedStartDate))
            {
                count++;
            }
        }
        return count;
    }
}