2008-10-10 162 views
4

我目前正在一個網站上跟蹤項目。其中可以創建服務級別協議(SLA)。這些配置可以在一週中的某個工作日進行,也可以在每一天進行時間安排。例如。週一可能在08:00至16:00之間,然後在週五從10:00至14:00。它們還根據優先級配置截止時間。例如。以「低」優先級創建的項目的截止時間爲兩週,而「高」優先級項目的截止時間爲四小時。計算工作天/小時的日期?

我遇到的問題是計算在前面描述的時間周圍的最後期限。假設我在週一14:00在「高」優先級創建項目。這意味着我有四個小時的這個項目。但由於工作時間的原因,我在星期一(直到16:00)有兩個小時,星期五又有兩個小時。這意味着截止日期必須定於週五12:00。

我花了相當多的時間搜索這個,我可以找到不少例子,找出在給定的開始結束日期之間有多少工作小時。我只是無法弄清楚如何將它轉換爲FINDING結束日期時間,給定一個開始時間和一段時間,直到截止日期。

日/時間跨度被存儲在格式SQL數據庫:

日(星期一例如1)StartHour EndHour

的StartHour/EndHour保存爲DateTime是否,但當然只時間部分很重要。

我認爲它的方式是,我必須以某種方式遍歷這些時間並執行一些日期時間計算。我無法弄清楚這些計算應該是什麼,最好的方法是什麼。

我在網站上找到了this Question,因爲我正在寫這個。這是我想要的,我現在正在玩它,但我仍然失去了如何在我的動態工作日/小時左右工作。

回答

1

有可能奏效,試着沿着這些路線思考一個遞歸解決方案:

public DateTime getDeadline(SubmitTime, ProjectTimeAllowed) 
{ 
    if (SubmitTime+ProjectTimeAllowed >= DayEndTime) 
      return getDeadline(NextDayStart, ProjectTimeAllowed-DayEndTime-SubmitTime) 
    else 
      return SubmitTime + ProjectTimeAllowed 
} 

顯然,這是相當粗糙的僞代碼。希望它能給你另一種思考問題的方式。

1

下面是我該怎麼做。算法是查看問題是否可以在今天結束,如果沒有,可以使用今天的所有時間來減少問題的剩餘時間,並在明天進行。

  1. 找到您要關閉該問題作爲一個時間跨度的時間(我打電話這個問題的剩餘時間)
  2. 對於每個工作日,創建只有起點和終點的時間的DateTime 。
  3. 將開始時間設置爲現在。
  4. 循環:
    1. 發現如今的減去今天的結束時間減去開始時間剩餘時間(結果應該是一個時間跨度)
    2. 如果今天的剩餘時間較發行的剩餘時間時,拿今天的日期和今天的開始時間+問題剩餘時間
    3. 如果問題的剩餘時間更長,請將問題的剩餘時間設置爲問題的剩餘時間減去今天的剩餘時間,移至明天,並轉至循環的頂部。
1

使用斯圖的answer爲起點,修改IsInBusinessHours函數查找你營業時間日期參數。像下面的過程可用於:

CREATE PROCEDURE [dbo].[IsInBusinessHours] 
    @MyDate DateTime 
AS 
BEGIN 
    SELECT  CASE Count(*) WHEN 0 THEN 0 ELSE 1 END AS IsBusinessHour 
FROM   WorkHours 
WHERE  (DATEPART(hour, StartHours) <= DATEPART(hour, @MyDate)) AND (DATEPART(hour, EndHours) > DATEPART(hour, @MyDate)) AND (Day = DATEPART(WEEKDAY, 
         @MyDate)) 
END 
2

下面是一些C#代碼可能有所幫助,也可能是乾淨得多,但它是一個快速的初稿。

class Program 
    { 
     static void Main(string[] args) 
     { 
      // Test 
      DateTime deadline = DeadlineManager.CalculateDeadline(DateTime.Now, new TimeSpan(4, 0, 0)); 
      Console.WriteLine(deadline); 
      Console.ReadLine(); 
     } 
    } 

    static class DeadlineManager 
    { 
     public static DateTime CalculateDeadline(DateTime start, TimeSpan workhours) 
     { 
      DateTime current = new DateTime(start.Year, start.Month, start.Day, start.Hour, start.Minute, 0); 
      while(workhours.TotalMinutes > 0) 
      { 
       DayOfWeek dayOfWeek = current.DayOfWeek; 
       Workday workday = Workday.GetWorkday(dayOfWeek); 
       if(workday == null) 
       { 
        DayOfWeek original = dayOfWeek; 
        while (workday == null) 
        { 
         current = current.AddDays(1); 
         dayOfWeek = current.DayOfWeek; 
         workday = Workday.GetWorkday(dayOfWeek); 
         if (dayOfWeek == original) 
         { 
          throw new InvalidOperationException("no work days"); 
         } 
        } 
        current = current.AddHours(workday.startTime.Hour - current.Hour); 
        current = current.AddMinutes(workday.startTime.Minute - current.Minute); 
       } 

       TimeSpan worked = Workday.WorkHours(workday, current); 
       if (workhours > worked) 
       { 
        workhours = workhours - worked; 
        // Add one day and reset hour/minutes 
        current = current.Add(new TimeSpan(1, current.Hour * -1, current.Minute * -1, 0)); 
       } 
       else 
       { 
        current.Add(workhours); 
        return current; 
       } 
      } 
      return DateTime.MinValue; 
     } 
    } 

    class Workday 
    { 
     private static readonly Dictionary<DayOfWeek, Workday> Workdays = new Dictionary<DayOfWeek, Workday>(7); 
     static Workday() 
     { 
      Workdays.Add(DayOfWeek.Monday, new Workday(DayOfWeek.Monday, new DateTime(1, 1, 1, 10, 0, 0), new DateTime(1, 1, 1, 16, 0, 0))); 
      Workdays.Add(DayOfWeek.Tuesday, new Workday(DayOfWeek.Tuesday, new DateTime(1, 1, 1, 10, 0, 0), new DateTime(1, 1, 1, 16, 0, 0))); 
      Workdays.Add(DayOfWeek.Wednesday, new Workday(DayOfWeek.Wednesday, new DateTime(1, 1, 1, 10, 0, 0), new DateTime(1, 1, 1, 16, 0, 0))); 
      Workdays.Add(DayOfWeek.Thursday, new Workday(DayOfWeek.Thursday, new DateTime(1, 1, 1, 10, 0, 0), new DateTime(1, 1, 1, 16, 0, 0))); 
      Workdays.Add(DayOfWeek.Friday, new Workday(DayOfWeek.Friday, new DateTime(1, 1, 1, 10, 0, 0), new DateTime(1, 1, 1, 14, 0, 0))); 
     } 

     public static Workday GetWorkday(DayOfWeek dayofWeek) 
     { 
      if (Workdays.ContainsKey(dayofWeek)) 
      { 
       return Workdays[dayofWeek]; 
      } 
      else return null; 
     } 

     public static TimeSpan WorkHours(Workday workday, DateTime time) 
     { 
      DateTime sTime = new DateTime(time.Year, time.Month, time.Day, 
       workday.startTime.Hour, workday.startTime.Millisecond, workday.startTime.Second); 
      DateTime eTime = new DateTime(time.Year, time.Month, time.Day, 
       workday.endTime.Hour, workday.endTime.Millisecond, workday.endTime.Second); 
      if (sTime < time) 
      { 
       sTime = time; 
      } 
      TimeSpan span = eTime - sTime; 
      return span; 
     } 

     public static DayOfWeek GetNextWeekday(DayOfWeek dayOfWeek) 
     { 
      int i = (dayOfWeek == DayOfWeek.Saturday) ? 0 : ((int)dayOfWeek) + 1; 
      return (DayOfWeek)i; 
     } 


     private Workday(DayOfWeek dayOfWeek, DateTime start, DateTime end) 
     { 
      this.dayOfWeek = dayOfWeek; 
      this.startTime = start; 
      this.endTime = end; 
     } 

     public DayOfWeek dayOfWeek; 
     public DateTime startTime; 
     public DateTime endTime; 
    }