根据工作日和小时+假期

时间:2017-06-02 10:24:04

标签: c# date datetime enum-flags

我想将正确的小时数绑定到正确的工作时间。工作周是从周一到周日。根据当天的时间,工作有不同的价格。基于完成当天时间的工作价格称为期间。我们使用24小时时间格式。

示例:

  • 期间1:周一至周五,00:00 - 07:00
  • 期间2:周一至周五,07:00-20:00
  • 期间3:周一至周五,20:00-22:00
  • 时段4:周一至周五,22:00 - 23:59(午夜)
  • 时段5:周六 - 周日,00:00 - 07:00
  • 期间6:周六 - 周日,07:00-22:00
  • 时段7:周六 - 周日,22:00-23:59(午夜)
  • 期间8:假日,00:00-23:59

期间如下所示:

public class Period
{
   public Period()
   {
   }

   public string Name { get; set; }
   public int Days { get; set; }
   public bool Holiday { get; set; }
   public TimeSpan Start { get; set; }
   public TimeSpan End { get; set; }
}

Days是int,但值将来自此枚举:

[Flags]
public enum Workweek
{
    Sunday = 1,
    Monday = 2,
    Tuesday = 4,
    Wednesday = 8,
    Thursday = 16,
    Friday = 32,
    Saturday = 64
}

当期间Days属性为62时,表示期间从星期一到星期五有效,此时天数为:65期间为星期六至星期日。当天数为:6时,周期为周一至周二。

Holiday为真时表示期间仅在假日有效。假日超过正常的一天或周末。

工作班次如下所示:

public class Work
{
   public Work()
   {
   }

   public string Name { get; set; }
   public DateTime Start { get; set; }
   public DateTime End { get; set; }
}

假设我有一个List<Work>和一个List<Period>,我如何将工作时间绑定到正确的时间段?每个期间都有不同的定价。

示例:

案例1:如果你在星期一的工作班次:15:00到23:00之间,那么工作班次将是这样的:

  • 时段2:5小时
  • 时段3:2小时
  • 时段4:1小时

案例1.1:如果特定星期一是假日,那么它将是:

  • 时段8:8小时

案例2:如果相反,工作从星期一的20:00开始,到第二天的04:00结束,结果将是:

  • 时段3:2小时
  • 时段4:2小时
  • 时段1:4小时

案例2.2:如果星期一是假日,那将是:

  • 时段8:4小时
  • 时段1:4小时

假期日为List<DateTime>

我如何将小时数与正确的时期相匹配?

到目前为止我尝试了什么:

Work work = new Work()
{
    Name = Demo,
    Star = new DateTime(2017,05,02,15,00,00);
    End = new DateTime(2017,05,02,23,00,00);
};

List<Period> periods = new List<Period>();

foreach (var period in periods)
{
    Workweek shiftDay = (Workweek)Enum.Parse(typeof(Workweek), work.Start.DayOfWeek, true); // i think this is wrong, because in the case where the end date is in the next day


    Workweek periodDay = (Workweek)period.Days;

    if ((shiftDay & periodDay) == shiftDay)
    {
        // the work matches the period
    }

}

我想我应该使用foreach并在开始日期和结束日期之间循环每一秒,并检查第二天是否与期间日相匹配。

这样的事情:

  public static IEnumerable<DateTime> EachSecond(this Work work)
    {
        DateTime currentSecond = new DateTime(work.Start.Year, work.Start.Month, work.Start.Day, work.Start.Hour, work.Start.Minute, work.Start.Second, work.Start.Millisecond);
        while (currentSecond <= wor.kEnd)
        {
            yield return currentSecond;
            currentSecond = currentSecond.AddSeconds(1);
        }
    }

   Work work = new Work()
   {
      Name = Demo,
      Star = new DateTime(2017,05,02,15,00,00);
      End = new DateTime(2017,05,02,23,00,00);
   };

    List<Period> periods = new List<Period>();

    foreach (var second in work.EachSecond())
    {
          Workweek shiftSecond = (Workweek)Enum.Parse(typeof(Workweek), second.DayOfWeek, true);

          foreach (var period in periods)
          {
               Workweek periodDay = (Workweek)period.Days;

               if ((shiftSecond & periodDay) == shiftSecond)
               {

               }
          }
    }

2 个答案:

答案 0 :(得分:1)

尝试这样的事情。我不知道为什么你需要一个自定义的工作周,当你可以使用标准的DayOfWeek。无论如何,我跟着你的请求。

application/json

答案 1 :(得分:1)

工作示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;

public class Program
{
    public static void Main( string[] args )
    {
        var periods = new List<Period> {
            new Period( "1", Days.Workdays, TimeSpan.FromHours(0), TimeSpan.FromHours(7) ),
            new Period( "2", Days.Workdays, TimeSpan.FromHours(7), TimeSpan.FromHours(20) ),
            new Period( "3", Days.Workdays, TimeSpan.FromHours(20), TimeSpan.FromHours(22) ),
            new Period( "4", Days.Workdays, TimeSpan.FromHours(22), TimeSpan.FromHours(24) ),
            new Period( "5", Days.Weekend, TimeSpan.FromHours(0), TimeSpan.FromHours(7) ),
            new Period( "6", Days.Weekend, TimeSpan.FromHours(7), TimeSpan.FromHours(22) ),
            new Period( "7", Days.Weekend, TimeSpan.FromHours(22), TimeSpan.FromHours(24) ),
            new Period( "8", Days.Holiday, TimeSpan.FromHours(0), TimeSpan.FromHours(24) ),
        };
        var holidays = new List<DateTime> {
            new DateTime( 2017, 1, 1 ),
            new DateTime( 2017, 1, 3 ),
            new DateTime( 2017, 1, 6 ),
        };

        var sc = new ShiftCalculator( periods, holidays );

        var shiftperiods = sc.GetShiftPeriods( new DateTime( 2016, 12, 31, 22, 00, 00 ), new DateTime( 2017, 01, 07, 08, 00, 00 ) ).ToList();

        foreach ( var sp in shiftperiods )
        {
            Console.WriteLine( "{0} - {1} - {2} - {3:00.00}h", sp.Period.Name, sp.Period.Days, sp.Start, sp.Duration.TotalHours );
        }

    }
}

[Flags]
enum Days : byte
{
    Sunday = 1,
    Monday = 2,
    Tuesday = 4,
    Wednesday = 8,
    Thursday = 16,
    Friday = 32,
    Saturday = 64,
    Holiday = 128,

    Workdays = Monday | Tuesday | Wednesday | Thursday | Friday,
    Weekend = Saturday | Sunday,
}

[DebuggerDisplay("{Name}: {Days} ({Start}-{End})")]
class Period
{
    public Period( string name, Days days, TimeSpan start, TimeSpan end )
    {
        if ( days.HasFlag( Days.Holiday ) && days != Days.Holiday )
            throw new ArgumentException( "days" );

        if ( start > end )
            throw new ArgumentException( "end" );

        Name = name;
        Days = days;
        Start = start;
        End = end;
    }

    public string Name { get; private set; }
    public Days Days { get; private set; }
    public TimeSpan Start { get; private set; }
    public TimeSpan End { get; private set; }
}

class ShiftPeriod
{
    public Period Period { get; set; }
    public DateTime Start { get; set; }
    public TimeSpan Duration { get; set; }
}

class ShiftCalculator
{
    private readonly List<Period> _periods;
    private readonly List<DateTime> _holidays;

    public ShiftCalculator( IEnumerable<Period> periods, IEnumerable<DateTime> holidays )
    {
        _periods = periods.ToList();
        _holidays = holidays.Select( e => e.Date ).ToList();
    }

    public IEnumerable<ShiftPeriod> GetShiftPeriods( DateTime start, DateTime end )
    {
        if ( start > end ) throw new ArgumentException( "end" );

        var current = start;

        while ( current < end )
        {
            var period = GetPeriodByDateTime( current );

            var next = current.Date + period.End;

            if ( next > end )
            {
                next = end;
            }

            yield return new ShiftPeriod
            {
                Period = period,
                Start = current,
                Duration = next - current,
            };

            current = next;
        }

    }

    private Days GetDayFromDateTime( DateTime datetime )
    {
        Days day;
        if ( _holidays.Contains( datetime.Date ) )
        {
            day = Days.Holiday;
        }
        else
        {
            switch ( datetime.DayOfWeek )
            {
                case DayOfWeek.Sunday:
                day = Days.Sunday;
                break;
                case DayOfWeek.Monday:
                day = Days.Monday;
                break;
                case DayOfWeek.Tuesday:
                day = Days.Tuesday;
                break;
                case DayOfWeek.Wednesday:
                day = Days.Wednesday;
                break;
                case DayOfWeek.Thursday:
                day = Days.Thursday;
                break;
                case DayOfWeek.Friday:
                day = Days.Friday;
                break;
                case DayOfWeek.Saturday:
                day = Days.Saturday;
                break;
                default:
                throw new InvalidOperationException();
            }
        }
        return day;
    }

    private Period GetPeriodByDateTime( DateTime datetime )
    {
        var day = GetDayFromDateTime( datetime );
        var timeOfDay = datetime.TimeOfDay;
        var period = _periods.Where(
            e => e.Days.HasFlag( day ) && e.Start <= timeOfDay && e.End > timeOfDay )
            .FirstOrDefault();
        if ( period == null )
        {
            throw new InvalidOperationException();
        }
        return period;
    }
}

.net fiddle

生成输出

7 - Weekend - 12/31/2016 10:00:00 PM - 02.00h
8 - Holiday - 1/1/2017 12:00:00 AM - 24.00h
1 - Workdays - 1/2/2017 12:00:00 AM - 07.00h
2 - Workdays - 1/2/2017 7:00:00 AM - 13.00h
3 - Workdays - 1/2/2017 8:00:00 PM - 02.00h
4 - Workdays - 1/2/2017 10:00:00 PM - 02.00h
8 - Holiday - 1/3/2017 12:00:00 AM - 24.00h
1 - Workdays - 1/4/2017 12:00:00 AM - 07.00h
2 - Workdays - 1/4/2017 7:00:00 AM - 13.00h
3 - Workdays - 1/4/2017 8:00:00 PM - 02.00h
4 - Workdays - 1/4/2017 10:00:00 PM - 02.00h
1 - Workdays - 1/5/2017 12:00:00 AM - 07.00h
2 - Workdays - 1/5/2017 7:00:00 AM - 13.00h
3 - Workdays - 1/5/2017 8:00:00 PM - 02.00h
4 - Workdays - 1/5/2017 10:00:00 PM - 02.00h
8 - Holiday - 1/6/2017 12:00:00 AM - 24.00h
5 - Weekend - 1/7/2017 12:00:00 AM - 07.00h
6 - Weekend - 1/7/2017 7:00:00 AM - 01.00h