2008-09-26 4 views
6

주어진 두 datetimes. 그들 사이의 근무 시간을 계산하는 가장 좋은 방법은 무엇입니까? 근무 시간은 월 8 - 5.30, 화요일 - 금 8.30 - 5.30이며, 잠재적으로 하루는 공휴일 일 수 있음을 고려하십시오.2 datetime 사이의 경과 근무 시간 계산

이것은 내 노력으로 비효율적이지만 비효율적이지만 반복 횟수와 IsWorkingDay 메서드가 DB에 도달하여 해당 날짜 시간이 공휴일인지 확인합니다.

누구나 어떤 최적화 나 대안을 제안 할 수 있습니까? 특히 IsWorkingDay 방법을 고려

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; 
     } 
+0

몇 개의 공휴일을 보유하고 계십니까? ; P – leppie

답변

1

그 날이 공휴일

경우 문제가 쿼리의 수보다는 데이터의 양이 경우 작업을 조회, 확인하기 위해 DB 안타 각 루프 반복에서 쿼리하는 대신 처음부터 필요한 하루 범위의 데이터베이스에서 데이터를 가져올 수 있습니다.

+0

확실히 나는 당신의 말을 개념적으로 이해합니다. 그러나 그것을 깔끔하게 구현하는 것이 문제입니다. 그리고 나는 당신이 질의를 무시하더라도 내 접근법이 여전히 좋지 않다고 생각합니다. – Dan

+0

하루를 허용하는 IsWorkingDay() 대신 날짜 범위를 허용하고 범위의 휴일 수를 반환하는 HolidayCount() 메서드를 구현하십시오. –

+0

솔루션의 효율성이 떨어지는 코드가 현명한 경우 더 많은 일 동안 증분 계산해야합니다. – Dan

3

최적화를 시작하기 전에 다음 두 가지 질문을하십시오.

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 

당신은 DAY

BY @start와 @end 그룹 간의 휴일 등 월요일, 화요일, 수요일에 떨어지는 휴일의 수를 계산하고, 휴일 FROM SELECT COUNT (DAY) 같은 것을 할 수 있습니다. 아마도 SQL을 단지 월요일과 월요일이 아닌 것으로 계산하는 방법일지도 모르지만, 지금은 아무것도 생각할 수 없습니다.

+0

예, 예, 이것은 제 질문을 피하는 것입니다. – Dan

+1

그것은 당신이하는 일에 달려 있습니다. 충분히 빠르게 작동한다면 적어도 비즈니스 관점에서 볼 때 더 이상 최적화 할 시점이 없습니다. –

+0

@CynicalTyler thats 왜이 질문을하고 있는지, 더 좋은 방법을 제안하십시오. 그렇지 않으면 당신의 시간 낭비와 광산. – Dan

1

TimeSpan 클래스를 살펴보십시오. 그것은 당신에게 2 시간 사이의 시간을 줄 것입니다.

단일 DB 호출은 두 번에 걸쳐 공휴일을 얻을 수도 있습니다.

SELECT COUNT(*) FROM HOLIDAY WHERE HOLIDAY BETWEEN @Start AND @End 

8을 곱하고 총 시간에서 뺍니다.

-Ian

편집 : 당신이 휴가의이 경우 응답에서 아래로는, 시간의 일정한 수 없습니다.당신은 HolidayStartHolidayEnd 시간을 DB에 유지할 수 있으며, 단지 db에 대한 호출로부터 리턴 할 수 있습니다. 주 루틴에 대해 정한 방법과 비슷한 시간을 계산하십시오.

+0

1. 해당 쿼리는 구현에 도움이되지 않습니다. 2. 모든 요일이 8 일이 아니며 날짜와 시간의 시작과 끝이 하루 중 한시간이 아닐 수도 있습니다. – Dan

+0

이안 (Ian)의 방위에서 2와 관련하여 귀하의 질문에 "주어진 두 날짜" 두 가지 datetimes되지 않습니다. – Powerlord

+0

@Bemrose가 수정 해 주셔서 감사합니다. iv가 변경했습니다. – Dan

0

@OregonGhost는 IsWorkingDay() 함수를 사용하여 하루를 받고 부울을 반환하는 대신 범위를 허용하고 범위 내의 공휴일 수를 제공하는 정수를 반환하는 HolidayCount() 함수를 사용한다고 설명했습니다. . 트릭은 경계 일 시작일과 종료일에 대한 부분 날짜를 처리하는 경우 해당 날짜가 자체 휴일인지 여부를 결정해야 할 수도 있습니다. 그러나 그때조차도 새로운 방법을 사용하여 을 최대로 세 번 호출해야합니다. 이 라인을 따라

0

시도 뭔가 :

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) 
+0

월요일에는 공휴일을 고려하지 않습니다. –

+0

또는 일수입니다. 또는 근무 시간 외 근무일 인 경우 – Dan

1

또한 재귀 해결책이있다. 재미 반드시 효율적이지,하지만 많은 :이 작업을 수행하는

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); 
} 
0

가장 효율적인 방법은 다음 주말이나 휴일 시간을 빼기, 총 시간의 차이를 계산하는 것입니다. 고려해야 할 몇 가지 엣지 케이스가 있지만 범위의 첫 번째와 마지막 날을 따로 따로 계산하여이를 단순화 할 수 있습니다.

Ian Jacobs에 의해 제안 된 COUNT (*) 방법은 공휴일을 계산하는 좋은 방법 인 것 같습니다. 당신이 무엇을 사용하든, 그것은 단지 전체 일을 처리 할 것이고, 당신은 시작과 끝 날짜를 별도로 커버해야합니다.

주말을 쉽게 계산할 수 있습니다. 당신이 일요일 6 월요일 0을 반환하는 함수 평일 (날짜)이있는 경우, 그것은 다음과 같습니다

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

참고 : (끝 - 시작), 문자 그대로 무언가로 대체되어서는 안된다 시간대를 일 단위로 계산합니다.

0

@ Ian의 쿼리를 사용하여 날짜 사이를 확인하여 근무일이 아닌 날을 확인하십시오. 그런 다음 시작 시간 또는 종료 시간이 휴무일인지 아닌지 알아 내고 차이를 뺍니다.

시작 시간이 토요일 정오이고 종료 시간이 월요일 정오 인 경우 쿼리는 2 일 후에 다시 48 시간 (2 x 24)을 계산해야합니다. IsWorkingDay (start)에 대한 쿼리가 false를 반환하면 시작부터 자정까지의 시간을 24에서 빼면 12 시간 또는 총 36 시간의 비 근무 시간이됩니다.

이제 근무 시간이 매일 같으면 비슷한 일을합니다. 근무 시간이 조금 흩어지면 더 많은 문제가 발생할 것입니다.

이상적으로는 두 시간 (또는 심지어 날짜) 사이의 모든 근무 시간을 제공하는 데이터베이스에 대한 단일 쿼리를 만드는 것이 이상적입니다. 그런 다음 해당 세트에서 로컬로 수학을 수행하십시오.

-1
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 

케이크 조각!

건배!

관련 문제