Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#-以天、小时和分钟计算sla,不包括非工作时间、周末和公共假日_C#_.net_Linq - Fatal编程技术网

C#-以天、小时和分钟计算sla,不包括非工作时间、周末和公共假日

C#-以天、小时和分钟计算sla,不包括非工作时间、周末和公共假日,c#,.net,linq,C#,.net,Linq,我在搜索stackoverflow,以找到与C#中要解决的类似问题的精确匹配问题和响应 虽然我发现这些问题有一些相似之处,但我找不到任何关于如何以天、小时和分钟为单位计算sla(不包括公共假日、周末和非工作时间)的问题和回答 例如,我已将票证的datetime提升为2019年2月21日10:00:00 pm,如果我只想添加n(在本例中为21)个工作小时数,不包括非工作时间、周末和公共假日,则以C#查找该票证的sla datetime 虽然我已经实现了一些只计算工作时间、周末的逻辑,但发现很难排除

我在搜索stackoverflow,以找到与C#中要解决的类似问题的精确匹配问题和响应

虽然我发现这些问题有一些相似之处,但我找不到任何关于如何以天、小时和分钟为单位计算sla(不包括公共假日、周末和非工作时间)的问题和回答

例如,我已将票证的datetime提升为2019年2月21日10:00:00 pm,如果我只想添加n(在本例中为21)个工作小时数,不包括非工作时间、周末和公共假日,则以C#查找该票证的sla datetime

虽然我已经实现了一些只计算工作时间、周末的逻辑,但发现很难排除公共假日。也要欣赏比长行函数更好、更简单、更容易理解的方法(可能使用linq)。感谢来自社区的任何示例代码

我已经从其他stackoverflow链接中得到了一个改进的工作解决方案,如下所示,但这需要进一步改进,以简化和解决任何可能出现的错误,例如,如果我们连续休假2天,然后从第3天开始计算sla,则此场景无法处理,等等

到目前为止,我得到的解决方案是:

public virtual DateTime AddWithinWorkingHours(DateTime start, TimeSpan offset)
    {
        //Get publicholidaysList from holiday table to not to include in working hour calculation
        var holidaysList = _holidayManager.GetHolidays().Result;

        // Don't start counting hours until start time is during working hours
        if (start.TimeOfDay.TotalHours > StartHour + HoursPerDay)
            start = start.Date.AddDays(1).AddHours(StartHour);
        if (start.TimeOfDay.TotalHours < StartHour)
            start = start.Date.AddHours(StartHour);
        if (start.DayOfWeek == DayOfWeek.Saturday)
            start.AddDays(2);
        //if it is a Sunday or holiday date, skip that date in workinghour calc
        else if (start.DayOfWeek == DayOfWeek.Sunday || holidaysList.Exists(hd=>hd.Date == start.Date))
            start.AddDays(1);
        // Calculate how much working time already passed on the first day
        TimeSpan firstDayOffset = start.TimeOfDay.Subtract(TimeSpan.FromHours(StartHour));
        // Calculate number of whole days to add
        int wholeDays = (int)(offset.Add(firstDayOffset).TotalHours / HoursPerDay);
        // How many hours off the specified offset does this many whole days consume?
        TimeSpan wholeDaysHours = TimeSpan.FromHours(wholeDays * HoursPerDay);
        // Calculate the final time of day based on the number of whole days spanned and the specified offset
        TimeSpan remainder = offset - wholeDaysHours;
        // How far into the week is the starting date?
        int weekOffset = ((int)(start.DayOfWeek + 7) - (int)DayOfWeek.Monday) % 7;
        // How many weekends are spanned?
        int weekends = (int)((wholeDays + weekOffset) / 5);
        // Calculate the final result using all the above calculated values
        return start.AddDays(wholeDays + weekends * 2).Add(remainder);
    } 
public virtual DateTime addwithin workinghours(DateTime start,TimeSpan offset)
{
//从假日表中获取PublicHolidays列表,以便不包括在工作时间计算中
var holidaysList=\u holidayManager.GetHolidays().Result;
//直到开始时间在工作时间内,才开始计算小时数
如果(start.TimeOfDay.TotalHours>StartHour+HoursPerDay)
开始=开始.Date.AddDays(1).AddHours(StartHour);
if(开始时间:一天的时间:总小时数<开始时间)
开始=开始.Date.AddHours(StartHour);
如果(start.DayOfWeek==DayOfWeek.Saturday)
开始。添加天数(2);
//如果是周日或假日日期,请在workinghour calc中跳过该日期
else如果(start.DayOfWeek==DayOfWeek.Sunday | | holidaysList.Exists(hd=>hd.Date==start.Date))
开始。添加天数(1);
//计算第一天已经过了多少工作时间
TimeSpan firstDayOffset=start.TimeOfDay.Subtract(TimeSpan.FromHours(StartHour));
//计算要添加的总天数
int wholeDays=(int)(offset.Add(firstDayOffset.TotalHours/HoursPerDay);
//这一整天要消耗多少小时的指定偏移量?
TimeSpan wholeDaysHours=TimeSpan.FromHours(wholeDays*Hours perday);
//根据跨越的天数和指定的偏移量计算一天中的最后时间
TimeSpan余数=偏移量-总天数;
//开始日期是多久?
int weekOffset=((int)(start.DayOfWeek+7)-(int)DayOfWeek.Monday)%7;
//有多少个周末?
int周末=(int)((全天+周末)/5);
//使用上述所有计算值计算最终结果
返回start.AddDays(全天+周末*2).Add(剩余);
} 

我实际上花了最后一个小时来实施这个解决方案,它结合了另一个stackoverflow问题()中的一个问题,该问题计算某个日期的工作时间+一块金块,根据指定的国家验证某个日期是否为假日。 首先安装熔核

PM> install-package Nager.Date
然后,我创建了3种方法来实现您的功能,但它很简单,您可以对其进行优化,以采用CountryCode以及一个工作日的小时数和开始时间,但我将其硬编码仅用于示例目的:

        private static DateTime AddWithinWorkingHours(DateTime start, TimeSpan offset)
        {
            const int hoursPerDay = 8;
            const int startHour = 9;

            // Don't start counting hours until start time is during working hours
            if (start.TimeOfDay.TotalHours > startHour + hoursPerDay)
                start = start.Date.AddDays(1).AddHours(startHour);
            if (start.TimeOfDay.TotalHours < startHour)
                start = start.Date.AddHours(startHour);

            start = CheckTillNoLongerHoliday(start);

            if (start.DayOfWeek == DayOfWeek.Saturday)
                start = start.AddDays(2);
            else if (start.DayOfWeek == DayOfWeek.Sunday)
                start = start.AddDays(1);

            //Saving this proccessed date to check later if there are more holidays
            var dateAfterArranges = start;

            // Calculate how much working time already passed on the first day
            TimeSpan firstDayOffset = start.TimeOfDay.Subtract(TimeSpan.FromHours(startHour));

            // Calculate number of whole days to add
            int wholeDays = (int)(offset.Add(firstDayOffset).TotalHours / hoursPerDay);

            // How many hours off the specified offset does this many whole days consume?
            TimeSpan wholeDaysHours = TimeSpan.FromHours(wholeDays * hoursPerDay);

            // Calculate the final time of day based on the number of whole days spanned and the specified offset
            TimeSpan remainder = offset - wholeDaysHours;

            // How far into the week is the starting date?
            int weekOffset = ((int)(start.DayOfWeek + 7) - (int)DayOfWeek.Monday) % 7;

            // How many weekends are spanned?
            int weekends = (int)((wholeDays + weekOffset) / 5);

            //Get the final date without the holidays
            start = start.AddDays(wholeDays + weekends * 2).Add(remainder);

            //Check again if in this timeSpan there were any more holidays
            return InPeriodCheckHolidaysOnWorkingDays(dateAfterArranges, start);
        }


        private static DateTime CheckTillNoLongerHoliday(DateTime date)
        {
            if (DateSystem.IsPublicHoliday(date, CountryCode.PT) && !DateSystem.IsWeekend(date, CountryCode.PT))
            {
                date = date.AddDays(1);
                date = CheckTillNoLongerHoliday(date);
            }

            return date;
        }


        private static DateTime InPeriodCheckHolidaysOnWorkingDays(DateTime start, DateTime end)
        {
            var publicHolidays = DateSystem.GetPublicHoliday(2019, CountryCode.PT);

            var holidaysSpent = publicHolidays.Where(x => x.Date.Date >= start.Date && x.Date.Date < end.Date);
            foreach (var holiday in holidaysSpent)
            {
                if (!DateSystem.IsWeekend(holiday.Date, CountryCode.PT))
                {
                    end = end.AddDays(1);
                    if (DateSystem.IsWeekend(end, CountryCode.PT))
                    {
                        end = end.AddDays(2);
                    }
                }
            }

            return end;
        }
private static DateTime addwithin workinghours(DateTime start,TimeSpan offset)
{
每小时常数=8;
常数int startHour=9;
//直到开始时间在工作时间内,才开始计算小时数
如果(start.TimeOfDay.TotalHours>startHour+hoursPerDay)
开始=开始.Date.AddDays(1).AddHours(startHour);
if(开始时间:一天的时间:总小时数<开始时间)
开始=开始.Date.AddHours(startHour);
开始=CheckTillNoLongerHoliday(开始);
如果(start.DayOfWeek==DayOfWeek.Saturday)
开始=开始。添加天数(2);
else if(start.DayOfWeek==DayOfWeek.Sunday)
开始=开始。添加天数(1);
//保存此已处理日期,以便稍后检查是否有更多假期
var dateAfterArranges=开始;
//计算第一天已经过了多少工作时间
TimeSpan firstDayOffset=start.TimeOfDay.Subtract(TimeSpan.FromHours(startHour));
//计算要添加的总天数
int wholeDays=(int)(offset.Add(firstDayOffset.TotalHours/hoursPerDay);
//这一整天要消耗多少小时的指定偏移量?
TimeSpan wholeDaysHours=TimeSpan.FromHours(wholeDays*Hours perday);
//根据跨越的天数和指定的偏移量计算一天中的最后时间
TimeSpan余数=偏移量-总天数;
//开始日期是多久?
int weekOffset=((int)(start.DayOfWeek+7)-(int)DayOfWeek.Monday)%7;
//有多少个周末?
int周末=(int)((全天+周末)/5);
//得到最后的日期,没有假期
开始=开始.AddDays(全天+周末*2).添加(剩余);
//再次检查此时间段内是否还有其他假期
在工作日内的定期检查日返回(安排日期后,开始);
}
专用静态日期时间检查TillNoLongerHoliday(日期时间日期)
{
如果(日期)
public void CalendarDateAddSample()
{
  CalendarDateAdd calendarDateAdd = new CalendarDateAdd();
  // weekdays
  calendarDateAdd.AddWorkingWeekDays();
  // holidays
  calendarDateAdd.ExcludePeriods.Add( new Day( 2011, 4, 5, calendarDateAdd.Calendar ) );
  // working hours
  calendarDateAdd.WorkingHours.Add( new HourRange( new Time( 08, 30 ), new Time( 12 ) ) );
  calendarDateAdd.WorkingHours.Add( new HourRange( new Time( 13, 30 ), new Time( 18 ) ) );

  DateTime start = new DateTime( 2011, 4, 1, 9, 0, 0 );
  TimeSpan offset = new TimeSpan( 22, 0, 0 ); // 22 hours

  DateTime? end = calendarDateAdd.Add( start, offset );

  Console.WriteLine( "start: {0}", start );
  // > start: 01.04.2011 09:00:00
  Console.WriteLine( "offset: {0}", offset );
  // > offset: 22:00:00
  Console.WriteLine( "end: {0}", end );
  // > end: 06.04.2011 16:30:00
}
    public DateTime? CalculateSLADueDate(DateTime slaStartDateUTC, double slaDays, TimeSpan workdayStartUTC, TimeSpan workdayEndUTC)
    {
        if ((slaDays < 0)
        || (workdayStartUTC > workdayEndUTC))
        {
            return null;
        }

        var dueDate = slaStartDateUTC;
        var tsWorkdayHours = (workdayEndUTC - workdayStartUTC);
        var tsSlaCount = TimeSpan.FromHours(slaDays * ((workdayEndUTC - workdayStartUTC)).TotalHours);

        //get list of public holidays from in-memory cache
        var blPublicHoliday = new PublicHoliday();
        IList<BusObj.PublicHoliday> publicHolidays = blPublicHoliday.SelectAll();

        do
        {
            if ((dueDate.DayOfWeek == DayOfWeek.Saturday)
            || (dueDate.DayOfWeek == DayOfWeek.Sunday)
            || publicHolidays.Any(x => x.HolidayDate == dueDate.Date)
            || ((dueDate.TimeOfDay >= workdayEndUTC) && (dueDate.TimeOfDay < workdayStartUTC)))
            {
                //jump to start of next day
                dueDate = dueDate.AddDays(1);
                dueDate = new DateTime(dueDate.Year, dueDate.Month, dueDate.Day, workdayStartUTC.Hours, workdayStartUTC.Minutes, workdayStartUTC.Seconds);
            }
            else if ((dueDate.TimeOfDay == workdayStartUTC) && (tsSlaCount >= tsWorkdayHours))
            {
                //add a whole working day
                dueDate = dueDate.AddDays(1);
                tsSlaCount = tsSlaCount.Subtract(tsWorkdayHours);
            }
            else if (dueDate.TimeOfDay == workdayStartUTC)
            {
                //end day - add remainder of time for final work day
                dueDate = dueDate.Add(tsSlaCount);
                tsSlaCount = tsSlaCount.Subtract(tsSlaCount);
            }
            else
            {
                if(workdayEndUTC > dueDate.TimeOfDay)
                {
                    //start day and still in business hours - add rest of today
                    tsSlaCount = tsSlaCount.Subtract(workdayEndUTC - dueDate.TimeOfDay);
                    dueDate = dueDate.Add(workdayEndUTC - dueDate.TimeOfDay);
                }

                if (tsSlaCount.Ticks > 0)
                {
                    //if theres more to process - jump to start of next day
                    dueDate = dueDate.AddDays(1);
                    dueDate = new DateTime(dueDate.Year, dueDate.Month, dueDate.Day, workdayStartUTC.Hours, workdayStartUTC.Minutes, workdayStartUTC.Seconds);
                }
            }
        }
        while (tsSlaCount.Ticks > 0);

        return dueDate;
    }
public static class DatetimeExtensionMethod
{
    public static TimeSpan LocalTimeSpanToUTC(this TimeSpan ts)
    {
        DateTime dt = DateTime.Now.Date.Add(ts);
        DateTime dtUtc = dt.ToUniversalTime();
        TimeSpan tsUtc = dtUtc.TimeOfDay;
        return tsUtc;
    }

    public static TimeSpan UTCTimeSpanToLocal(this TimeSpan tsUtc)
    {
        DateTime dtUtc = DateTime.UtcNow.Date.Add(tsUtc);
        DateTime dt = dtUtc.ToLocalTime();
        TimeSpan ts = dt.TimeOfDay;
        return ts;
    }
}