4

私は現在、プロジェクトを追跡するための Web サイトに取り組んでいます。その中で、サービス レベル アグリーメント (SLA) を作成できます。これらは、プロジェクトに取り組むことができる曜日と、それらの各日のタイムスパンで構成できます。例えば。月曜日は 08:00 から 16:00 の間、金曜日は 10:00 から 14:00 の間です。また、優先度に応じて締め切り時間も設定されています。例えば。優先度「低」で作成されたプロジェクトの締め切り時間は 2 週間で、優先度「高」のプロジェクトの締め切り時間は 4 時間です。

私が抱えている問題は、前述の時間前後の締め切りを計算することです。月曜日の 14:00 に優先度「高」のプロジェクトを作成するとします。つまり、このプロジェクトには 4 時間かかります。でも勤務時間のせいで、月曜日に2時間(16時まで)、金曜日にさらに2時間あります。つまり、締め切りは金曜日の 12:00 に設定する必要があります。

私はこれをグーグルで検索するのにかなりの時間を費やしましたが、特定の開始日と終了日の間にどれくらいの労働時間があるかを調べる例をかなり見つけることができます. 開始時刻と締め切りまでの時間が与えられた場合、それを終了日時の検索に変換する方法がわかりません。

日/タイムスパンは、SQL データベースに次の形式で格納されます。

Day(例: 月曜日は 1) StartHour EndHour

StartHour/EndHour は DateTimes として保存されますが、もちろん時間の部分だけが重要です。

私の考えでは、これらの時間をどうにかして反復し、日時の計算を行う必要があります。それらの計算がどうあるべきか、最善の方法が何であるかを完全に理解することはできません。

これを書いているときに、サイトでこの質問を見つけました。それは私が望んでいるものであり、現在それで遊んでいますが、動的な勤務日/時間に合わせて正確に機能させる方法についてはまだ迷っています.

4

4 に答える 4

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;
    }
于 2008-10-10T19:46:14.143 に答える
1

Stuの回答を開始点として使用して、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
于 2008-10-10T19:43:07.817 に答える
1

これが私がそれを行う方法です。アルゴリズムは、問題が今日クローズできるかどうかを確認し、そうでない場合は、今日の時間をすべて使用して問題の残り時間を減らし、明日に進みます。

  1. 課題をクローズする必要がある時間を TimeSpan として見つけます (これを課題の残り時間と呼んでいます)
  2. 営業日ごとに、開始時刻と終了時刻のみを持つ DateTime を作成します。
  3. 開始時刻を今に設定します。
  4. ループ:
    1. 今日の終了時刻から開始時刻を差し引いて、今日の残り時間を見つけます (結果は TimeSpan になります)。
    2. 今日の残り時間が問題の残り時間よりも大きい場合は、今日の日付と今日の開始時刻 + 問題の残り時間を取る
    3. 問題の残り時間が大きい場合は、問題の残り時間を問題の残り時間から今日の残り時間を引いたものに設定し、明日に移動して、ループの先頭に移動します。
于 2008-10-10T19:35:09.500 に答える
1

機能する可能性のある再帰的なソリューションがあります。次の行に沿って考えてみてください。

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

明らかに、これは非常に大雑把な疑似コードです。問題について考える別の方法を提供してくれることを願っています。

于 2008-10-10T17:17:58.920 に答える