簡體   English   中英

計算工作日/小時左右的日期?

[英]Calculating a date around working days/hours?

我目前正在一個網站上跟蹤項目。 在其中,可以創建服務水平協議(SLA)。 這些可以配置項目可以處理的星期幾,以及每個日期的時間跨度。 例如。 周一可能是08:00至16:00,周五10:00至14:00。 它們還根據優先級配置了截止時間。 例如。 以“低”優先級創建的項目的截止時間為兩周,具有“高”優先級的項目的截止日期為四小時。

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

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

day / timespans以以下格式存儲在sql數據庫中:

一天(例如,星期一為1)StartHour EndHour

StartHour / EndHour保存為DateTimes,但當然只有時間部分很重要。

我想的方式是,我必須以某種方式迭代這些時間並進行一些日期時間計算。 我只是無法弄清楚那些計算應該是什么,最好的方法是什么。

在我寫這篇文章的時候,我在網站上發現了這個問題 這是我想要的東西,我現在正在玩它,但我仍然迷失在如何讓它在我的動態工作日/小時內工作。

這里有一些可能有用的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;
    }

有一個遞歸的解決方案可以工作,嘗試思考這些方面:

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

顯然這是非常粗糙的偽代碼。 希望它只是給你另一種思考問題的方法。

這是我將如何做到這一點。 該算法是為了查看問題是否可以在今天關閉,如果沒有,請使用今天的所有時間來減少問題的剩余時間並轉到明天。

  1. 找到你必須以TimeSpan關閉問題的時間(我稱之為問題的剩余時間)
  2. 對於每個工作日,創建一個僅包含開始和結束時間的DateTime。
  3. 將開始時間設置為現在。
  4. 環:
    1. 通過減去今天的結束時間減去開始時間來查找今天的剩余時間(結果應該是TimeSpan)
    2. 如果今天的剩余時間大於問題的剩余時間,請考慮今天的日期和今天的開始時間+問題剩余時間
    3. 如果問題的剩余時間更長,請將問題的剩余時間設置為問題的剩余時間減去今天的剩余時間,移至明天,然后轉到循環的頂部。

使用Stu的答案作為起點,修改IsInBusinessHours函數以查找date參數的工作時間。 可以使用如下過程:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM