2008-10-10 3 views
4

В настоящее время я работаю над веб-сайтом для отслеживания проектов. В нем можно создать соглашения об уровне обслуживания (SLA). Они настраиваются с днями недели, когда проект может быть обработан, а также время в каждый из этих дней. Например. в понедельник он может быть между 08:00 и 16:00, а затем в пятницу с 10:00 до 14:00. Они также настроены с временным временем в зависимости от приоритета. Например. проект, созданный с приоритетом «Низкий», имеет крайний срок в две недели, а проект с приоритетом «Высокий» имеет предельный срок в четыре часа.Расчет даты вокруг рабочих дней/часов?

Проблема, с которой я столкнулся, заключается в расчете предельного срока ВО ВРЕМЯ часов, описанных ранее. Скажем, я создаю проект в понедельник в 14:00 с приоритетом «Высокий». Это означает, что у меня есть четыре часа для этого проекта. Но из-за рабочего времени у меня есть два часа в понедельник (до 16:00), а затем еще два часа в пятницу. Это означает, что Крайний срок должен быть установлен в пятницу в 12:00.

Я потратил довольно много времени на это, и я могу найти немало примеров того, как много рабочих часов между датой окончания окончания начала. Я просто не могу понять, как преобразовать его в FINDING окончание datetime, учитывая начальное время и количество времени до крайнего срока.

На следующий день/timespans хранятся в базе данных SQL в формате:

день (. Eg 1 понедельник) StartHour EndHour

StartHour/EndHour сохраняются как DateTimes, но, конечно, только важная часть времени.

Как я понимаю, мне нужно как-то перебирать эти времена и делать некоторые вычисления в датах. Я просто не могу понять, какими должны быть эти вычисления, что лучший способ.

Я нашел this Question здесь, на сайте, как я писал это. Это то, что я хочу, и сейчас я играю с ним, но я все еще теряю то, как именно заставить его работать вокруг моих динамических рабочих дней/часов.

ответ

1

Там рекурсивное решение, которое может работать, попробуйте думать вдоль этих линий:

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

Очевидно, что это довольно грубый псевдокод. Надеюсь, это просто даст вам еще один способ подумать о проблеме.

1

Вот как я это сделаю. Алгоритм заключается в том, чтобы проверить, может ли проблема быть закрыта сегодня, а если нет, используйте все сегодняшнее время, чтобы сократить оставшееся время проблемы и перейти к завтрашнему дню.

  1. Найдите время нужно закрыть этот вопрос как TimeSpan (я называю это оставшееся время этого вопроса в)
  2. Для каждого рабочего дня, создать DateTime, который имеет только время начала и конца ,
  3. Установите время начала до настоящего времени.
  4. Loop:
    1. Найти сегодня оставшееся время путем вычитания сегодняшнего времени окончания минус начальное время (результат должен быть TimeSpan)
    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; 
    }