计算工作天/小时的日期?
我目前正在一个网站上跟踪项目。其中可以创建服务级别协议(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,因为我正在写这个。这是我想要的,我现在正在玩它,但我仍然失去了如何在我的动态工作日/小时左右工作。
有可能奏效,试着沿着这些路线思考一个递归解决方案:
public DateTime getDeadline(SubmitTime, ProjectTimeAllowed)
{
if (SubmitTime+ProjectTimeAllowed >= DayEndTime)
return getDeadline(NextDayStart, ProjectTimeAllowed-DayEndTime-SubmitTime)
else
return SubmitTime + ProjectTimeAllowed
}
显然,这是相当粗糙的伪代码。希望它能给你另一种思考问题的方式。
下面是我该怎么做。算法是查看问题是否可以在今天结束,如果没有,可以使用今天的所有时间来减少问题的剩余时间,并在明天进行。
- 找到您要关闭该问题作为一个时间跨度的时间(我打电话这个问题的剩余时间)
- 对于每个工作日,创建只有起点和终点的时间的DateTime 。
- 将开始时间设置为现在。
- 循环:
- 发现如今的减去今天的结束时间减去开始时间剩余时间(结果应该是一个时间跨度)
- 如果今天的剩余时间较发行的剩余时间时,拿今天的日期和今天的开始时间+问题剩余时间
- 如果问题的剩余时间更长,请将问题的剩余时间设置为问题的剩余时间减去今天的剩余时间,移至明天,并转至循环的顶部。
使用斯图的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
下面是一些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;
}