任务占用时间的算法

jma*_*erx 8 c# asp.net algorithm

Edit:
Steps:
Start at target day. 
Then move backwards until no events are carried over from another day.
From there, start counting hours, and keep track of carried over hours. 
Day cannot last more than ActualDayLength()
Then, once you know that, work your way back to target and then calculate actual occupied hours.
Run Code Online (Sandbox Code Playgroud)

我有任务放在日历上:

在此输入图像描述

现在让我给出一些背景:每天"持续"7.5小时.但是我使用了一个名为DayHours的变量(现在是7.5).(DayHours也用于下面描述的锁定时间).

此日历的目标是为员工安排7.5小时的工作日.

我需要的是一种算法,可以正确地告诉我一天中实际占用了多少小时.

这看起来很简单,但实际上是非常递归的.

首先,几个笔记.你会发现案件经理在14小时内可以在​​7.5小时的2天内完成,剩下1小时.它被延长到3天,因为1. Schedule,是5个小时,并且2.在当天的前任任务完成之前无法启动.

还有锁定时间的概念.在紫色是锁定时间.这是10个小时的锁定时间.这意味着,在12日,我只能做(7.5 - 7.5)小时的工作,而周一,只能做(7.5 - 2.5)小时.

我已经有了一个函数来计算实际一天的可用时间来解释这个问题:

public decimal GetActualDayLength(DateTime day, Schedule s)
{
    var e = Schedules.GetAllWithElement();
    var t = Timeless(day);
    var locked = from p in e
                 where p.EmployeID == s.EmployeID &&
                 ((p.DateTo.Value.Date) >= t &&
                 Timeless(p.DateFrom.Value) <= t) &&
                 p.IsLocked
                 select p;

    decimal hrs = 0.0M;

    foreach (var c in locked)
    {
        if (c.Hours.Value <= DaysManager.GetDayHours())
            hrs += c.Hours.Value;
        else if (Timeless(c.DateTo.Value) != t)
            hrs += DaysManager.GetDayHours();
        else
        {
            if (c.Hours.Value % DaysManager.GetDayHours() > 0)
                hrs += c.Hours.Value % DaysManager.GetDayHours();
            else
                hrs += DaysManager.GetDayHours();
        }
    }

    return DaysManager.GetDayHours() - hrs;
}
Run Code Online (Sandbox Code Playgroud)

还有携带时间的概念.

这是一个例子:

在此输入图像描述

现在让我们在18日星期四(18日有1.案例):

要查找当天为该员工提供的小时数,我们需要先查看当天开始,结束或落下的任务.

我不知道18日我可以做多少小时,因为那天结束的任务可能有几个小时.所以我去看看Perform unit test的开始日.我无法弄清楚这一点,因为NWDM当天结束,而且它可能有几个小时.

所以现在我去评估NWDM.啊,这一天没有结束,所以我知道时间表将需要5/7.5小时.

所以我继续前进,每天增加7.5小时.

然后我到达NWDM的最后一天.直到那时,我工作了5 + 7.5 + 7.5 + 7.5小时,

所以我放了27.5个小时,所以我会在22日(30 - 27.5 = 2.5h)完成它.所以我还有5个小时的时间来完成执行单元测试.

这意味着我需要1.5小时才能完成它.现在案例是1小时.

如果情况是7.5 - 1.5或更高,我们说这一天已满并返回DayHours.

因此,我们完成了.返回值为1.5 + 1 = 2.5.

该函数应该看起来像这样:

public decimal GetHours(IEnumerable<Schedule> s, DateTime today)
{
    DateTime t = Timeless(today);

    decimal hrs = 0;
    foreach (Schedule c in s)
    {
        if (c.Hours.Value <= DaysManager.GetDayHours())
            hrs += c.Hours.Value;
        else if (Timeless(c.DateTo.Value) != t)
            hrs += DaysManager.GetDayHours();
        else
        {
            if (c.Hours.Value % DaysManager.GetDayHours() > 0)
                hrs += c.Hours.Value % DaysManager.GetDayHours();
            else
                hrs += DaysManager.GetDayHours();
        }
    }
    return hrs;
}
Run Code Online (Sandbox Code Playgroud)

为了获得在给定日期内开始,结束或落下的事件,我使用:

public IEnumerable<Schedule> GetAllToday(DateTime date, int employeeID, Schedule current)
{
    DateTime t = Timeless(date);
    int sid = current == null ? -1 : current.ScheduleID;

    var e = Schedules.GetAllWithElement();
    return from p in e
           where (((Timeless(p.DateTo.Value) >= t &&
           Timeless(p.DateFrom.Value) <= t &&
           p.EmployeID == employeeID) &&
           (p.IsLocked || (Timeless(p.DateFrom.Value) < t &&
           (sid == -1 ? true : Timeless(p.DateFrom.Value) < current.DateFrom.Value)) ||
           bumpedList.Any(d => d.ScheduleID == p.ScheduleID)) &&
           p.ScheduleID != sid) ||
           ((Timeless(p.DateTo.Value) >= t &&
           (Timeless(p.DateFrom.Value) == t || (Timeless(p.DateFrom.Value) < t &&
           (sid == -1 ? true : Timeless(p.DateFrom.Value) > current.DateFrom.Value))) &&
           p.EmployeID == employeeID) &&
           !p.IsLocked &&
           !bumpedList.Any(d => d.ScheduleID == p.ScheduleID) &&
           p.ScheduleID != sid)) &&
           p.ScheduleID != sid
           select p;
        }
Run Code Online (Sandbox Code Playgroud)

附表有以下相关领域:

DateFrom
DateTo
Hours
EmployeeID
Run Code Online (Sandbox Code Playgroud)

附表看起来像:

[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Schedule")]
public partial class Schedule : INotifyPropertyChanging, INotifyPropertyChanged
{
    private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
    private int _ScheduleID;
    private System.Nullable<System.DateTime> _DateFrom;
    private System.Nullable<decimal> _Hours;
    private System.Nullable<int> _EmployeID;
    private System.Nullable<int> _RecurringID;
    private System.Nullable<int> _Priority;
    private System.Nullable<System.DateTime> _DateTo;
    private bool _IsLocked;
    private System.Nullable<int> _BumpPriority;
    private EntitySet<Case> _Cases;
    private EntitySet<Project> _Projects;
    private EntitySet<Task> _Tasks;
    private EntitySet<Task> _Tasks1;
    private EntityRef<Employee> _Employee;
    private EntityRef<Recurring> _Recurring;

    #region Extensibility Method Definitions
    partial void OnLoaded();
    partial void OnValidate(System.Data.Linq.ChangeAction action);
    partial void OnCreated();
    partial void OnScheduleIDChanging(int value);
    partial void OnScheduleIDChanged();
    partial void OnDateFromChanging(System.Nullable<System.DateTime> value);
    partial void OnDateFromChanged();
    partial void OnHoursChanging(System.Nullable<decimal> value);
    partial void OnHoursChanged();
    partial void OnEmployeIDChanging(System.Nullable<int> value);
    partial void OnEmployeIDChanged();
    partial void OnRecurringIDChanging(System.Nullable<int> value);
    partial void OnRecurringIDChanged();
    partial void OnPriorityChanging(System.Nullable<int> value);
    partial void OnPriorityChanged();
    partial void OnDateToChanging(System.Nullable<System.DateTime> value);
    partial void OnDateToChanged();
    partial void OnIsLockedChanging(bool value);
    partial void OnIsLockedChanged();
    partial void OnBumpPriorityChanging(System.Nullable<int> value);
    partial void OnBumpPriorityChanged();
    #endregion

    public Schedule()
    {
        this._Cases = new EntitySet<Case>(new Action<Case>(this.attach_Cases), new Action<Case>(this.detach_Cases));
        this._Projects = new EntitySet<Project>(new Action<Project>(this.attach_Projects), new Action<Project>(this.detach_Projects));
        this._Tasks = new EntitySet<Task>(new Action<Task>(this.attach_Tasks), new Action<Task>(this.detach_Tasks));
        this._Tasks1 = new EntitySet<Task>(new Action<Task>(this.attach_Tasks1), new Action<Task>(this.detach_Tasks1));
        this._Employee = default(EntityRef<Employee>);
        this._Recurring = default(EntityRef<Recurring>);
        OnCreated();
    }
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以帮我开发一个可以做到这一点的算法吗?

man*_*cze 1

尽管你的问题很复杂并且解释得不是很清楚,但我会尽力回答。或者更准确地说,提示您应该如何分解和解决它(或者我将如何解决它)。

我需要的是一种能够正确告诉我一天实际占用了多少小时的算法。

DateTo起初,如果您有可用的价值,我没有看到真正的问题Schedule。除非它等于DateFrom+ Hours。在这种情况下,它并不反映真实的DateTo但有些不相关的价值。

我假设任何Schedule是由开始时间DateFrom和持续时间定义的HoursDateTo计算价值,高效计算才是问题的真正核心。

所以我认为这个函数获取任何时间范围内的可用时间非常简单。用伪代码来说:

TimeSpan GetAvailableTime(DateRange range)
    var tasks = FindIntersectingTasks(range)

    ' now the algorithm which finds available hours on given collection 
    ' of tasks
    ' firstly - we need to determine relevant ranges which intersect 
    '           with given range
    var occupiedRanges = New List<DateRange>(tasks.Count)
    for each task in tasks
        var intersection = range.Intersect(
            new DateRange(task.DateFrom, task.DateTo)
        )

        if Not intersection.IsEmpty
            occupiedRanges.Add(intersection)
        end 
    end 

    ' secondly - sort ranges by start so we can easily merge them
    ranges.Sort(range => range.DateFrom)
    var mergedOccupiedRanges = new List(DateRange)

    ' thirdly - merge ranges so that we have collection with 
    '           non-overlaping ranges (and also sorted)
    for each occupiedRange in occupiedRanges
        ' range may merge only it there is non-empty intersection
        if occupiedRange.CanMerge(mergedOccupiedRanges.Last)
             var mergedRange = range.Merge(mergedOccupiedRanges.Last)
             mergedOccupiedRanges.RemoveLast()
             mergedOccupiedRanges.Add(mergedRange)
        end
    end 

    ' fourthly - it is simple now to determine available/occupied hours
    var timeAvailable = range.Duration
    for each mergedRange in mergedOccupiedRanges
        timeAvailable -= mergedRange.Duration
    end

    return timeAvailable
end

IEnumerable<Schedule> FindIntersectingTasks(DateRange range)
    return From schedule In allEvents
           Where schedule.DateFrom <= range.To 
               And schedule.DateTo >= range.From
end
Run Code Online (Sandbox Code Playgroud)

您可能需要进行一些调整,因为DateTime预计每天 24 小时都是正常的。