C# 计算2个datetime之间经过的工作时间

C# 计算2个datetime之间经过的工作时间,c#,datetime,date,C#,Datetime,Date,两次约会。计算他们之间工作时间的最佳方法是什么。考虑到工作时间是周一8-5.30,周二-周五8.30-5.30,并且任何一天都可能是公共假日 这是我的努力,看起来效率非常低,但就迭代次数而言,IsWorkingDay方法点击DB查看datetime是否为公共假日 有人能提出任何优化或替代方案吗 public decimal ElapsedWorkingHours(DateTime start, DateTime finish) { decimal co

两次约会。计算他们之间工作时间的最佳方法是什么。考虑到工作时间是周一8-5.30,周二-周五8.30-5.30,并且任何一天都可能是公共假日

这是我的努力,看起来效率非常低,但就迭代次数而言,IsWorkingDay方法点击DB查看datetime是否为公共假日

有人能提出任何优化或替代方案吗

 public decimal ElapsedWorkingHours(DateTime start, DateTime finish)
        {

            decimal counter = 0;

            while (start.CompareTo(finish) <= 0)
            {   
                if (IsWorkingDay(start) && IsOfficeHours(start))
                {
                    start = start.AddMinutes(1);
                    counter++;
                }
                else
                {
                    start = start.AddMinutes(1);
                }
            }

            decimal hours;

            if (counter != 0)
            {
                hours = counter/60;
            }

            return hours;
        }
公共十进制ElapsedWorkingHours(日期时间开始,日期时间结束)
{
十进制计数器=0;
while(开始。比较到(完成)
特别是考虑到IsWorkingDay方法会点击DB以查看该天是否为公共假日


如果问题是查询的数量而不是数据量,则在开始时从数据库中查询所需的整个工作日范围的工作日数据,而不是在每个循环迭代中查询。

在开始优化之前,问自己两个问题

a) 它有用吗

b) 是不是太慢了

只有当两个问题的答案都是“是”时,您才准备好开始优化

除此之外

  • 你只需要担心开始日和结束日的分钟数和小时数。中间的日子显然是整整9/9.5小时,除非是节假日或周末
  • 不需要查看周末是否是假日
我会这样做的

// Normalise start and end    
while start.day is weekend or holiday, start.day++, start.time = 0.00am
    if start.day is monday,
        start.time = max(start.time, 8am)
    else
        start.time = max(start.time, 8.30am)
while end.day is weekend or holiday, end.day--, end.time = 11.59pm
end.time = min(end.time, 5.30pm)

// Now we've normalised, is there any time left?    
if start > end
   return 0

// Calculate time in first day    
timediff = 5.30pm - start.time
day = start.day + 1
// Add time on all intervening days
while(day < end.day)
   // returns 9 or 9.30hrs or 0 as appropriate, could be optimised to grab all records
   // from the database in 1 or 2 hits, by counting all intervening mondays, and all
   // intervening tue-fris (non-holidays)
   timediff += duration(day) 

// Add time on last day
timediff += end.time - 08.30am
if end.day is Monday then
    timediff += end.time - 08.00am
else
    timediff += end.time - 08.30am

return timediff
//正常化开始和结束
当start.day是周末或假日时,start.day++,start.time=0.00am
如果开始日是星期一,
start.time=最大值(start.time,上午8点)
其他的
start.time=最大值(start.time,上午8:30)
当end.day为周末或假日时,end.day--,end.time=11.59pm
结束时间=分钟(结束时间,下午5:30)
//现在我们已经恢复正常了,还有时间吗?
如果开始>结束
返回0
//计算第一天的时间
timediff=5.30pm-start.time
天=开始。天+1
//在所有中间日期添加时间
而(日<结束日)
//返回9或9.30小时或0(视情况而定),可以优化以获取所有记录
//从数据库中点击1或2次,通过计算所有中间的星期一和所有
//星期二至五(非节假日)
timediff+=持续时间(天)
//添加最后一天的时间
timediff+=结束时间-上午8时30分
如果今天是星期一,那么
timediff+=结束时间-上午8时
其他的
timediff+=结束时间-上午8时30分
返回时间差
你可以这样做 从假日中选择计数(天),其中假日按天在@Start和@End组之间


计算星期一、星期二、星期三等的假期数。这可能是一种让SQL只计算星期一和非星期一的方法,但目前还想不出任何东西。

看看TimeSpan类。这将为您提供任意两次之间的小时数

一次DB呼叫也可以在您的两次通话之间获得假期;大致如下:

SELECT COUNT(*) FROM HOLIDAY WHERE HOLIDAY BETWEEN @Start AND @End
把这个数字乘以8,然后从你的总小时数中减去它

-伊恩


编辑:作为对以下内容的回应,如果你是假日,那么你的假期不是固定的小时数。你可以在数据库中保留一个
假日开始
和一个
假日结束
时间,并且只需从数据库调用中返回它们。做一个小时计数,类似于你为主例程确定的任何方法。

@OregonGhost所说的,不是在接受一天并返回布尔值时使用IsWorkingDay()函数,而是使用HolidayCount()函数函数,该函数接受一个范围并返回一个整数,给出该范围内的假期数。这里的诀窍是,如果您处理的是边界开始日和结束日的部分日期,您可能仍然需要确定这些日期本身是否为假期。但即使如此,您也可以使用新方法确保最多需要三天调用数据库。

尝试以下方法:

TimeSpan = TimeSpan Between Date1 And Date2
cntDays = TimeSpan.Days 
cntNumberMondays = Iterate Between Date1 And Date2 Counting Mondays 
cntdays = cntdays - cntnumbermondays
NumHolidays = DBCall To Get # Holidays BETWEEN Date1 AND Date2
Cntdays = cntdays - numholidays 
numberhours = ((decimal)cntdays * NumberHoursInWorkingDay )+((decimal)cntNumberMondays * NumberHoursInMondayWorkDay )

还有递归解决方案。不一定高效,但很有趣:

public decimal ElapseddWorkingHours(DateTime start, DateTime finish)
{
    if (start.Date == finish.Date)
        return (finish - start).TotalHours;

    if (IsWorkingDay(start.Date))
        return ElapsedWorkingHours(start, new DateTime(start.Year, start.Month, start.Day, 17, 30, 0))
            + ElapsedWorkingHours(start.Date.AddDays(1).AddHours(DateStartTime(start.Date.AddDays(1)), finish);
    else
        return ElapsedWorkingHours(start.Date.AddDays(1), finish);
}

<> P>最有效的方法是计算总时差,然后减去周末或假日的时间。有很多边缘情况需要考虑,但是你可以通过计算范围的第一天和最后几天来简化计算。 所建议的COUNT(*)方法似乎是计算假期的一个好方法。无论您使用什么方法,它都只处理整天,您需要分别涵盖开始日期和结束日期

计算周末是很容易的;如果您有一个函数Weekday(date),它返回0表示星期一,返回6表示星期天,则它如下所示:

saturdays = ((finish - start) + Weekday(start) + 2) / 7;
sundays = ((finish - start) + Weekday(start) + 1) / 7;

注意:(finish-start)不是字面意义上的,用计算时间跨度(以天为单位)来代替它。

使用@Ian的查询来检查日期之间的差异,找出哪些天不是工作日。然后做一些数学运算,找出你的开始时间或结束时间是否在非工作日,并减去差值

因此,如果开始时间是星期六中午,结束时间是星期一中午,则查询应返回2天,从中计算48小时(2 x 24)。如果您在IsWorkingDay(开始)上的查询返回false,则从24减去从开始到午夜的时间,这将给您12小时,或36小时的总非工作时间

现在,如果你每天的办公时间都一样,你就会做类似的事情。如果你的办公时间有点分散,你就会有更多的麻烦

理想情况下,对数据库进行一次查询,查询出两次(甚至两次日期)之间的所有办公时间。然后从该集合中进行本地计算。

Dim totalMinutes As Integer=0
Dim totalMinutes As Integer = 0

For minute As Integer = 0 To DateDiff(DateInterval.Minute, contextInParameter1, contextInParameter2)
    Dim d As Date = contextInParameter1.AddMinutes(minute)
    If d.DayOfWeek <= DayOfWeek.Friday AndAlso _
       d.DayOfWeek >= DayOfWeek.Monday AndAlso _
       d.Hour >= 8 AndAlso _
       d.Hour <= 17 Then
        totalMinutes += 1
    Else
        Dim test = ""
    End If
Next minute

Dim totalHours = totalMinutes / 60
对于分钟作为整数=0到DateDiff(DateInterval.minute、contextInParameter1、contextInParameter2) Dim d As Date=contextInParameter1.AddMinutes(分钟) 如果d.DayOfWeek=DayOfWeek.Monday和Also_ d、 小时>=8安达索_ d、 多少小时