日历与重复项目

时间:2011-06-14 09:34:55

标签: c# algorithm calendar

您好我正在尝试创建一个功能,其中用户添加将在中心间隔重复的项目。但是我在数学方面遇到了一些问题,所以我希望你们中的一些人之前做过类似的事情。

它基于Google日历,可以通过4种不同的方法重复事件。

  1. 每日
  2. 每周
  3. 每月
  4. 每年
  5. 然后用户然后定义用户想要的重复类型,每天都很简单,它只是每一天。 现在每周更棘手,因为用户可以选择2个选项

    1. 周间隔(每隔一周重复,或第三周等)
    2. 本周的哪一天(周一,周四等)
    3. 每月和每年只有1个选项

      1. 月/年间隔
      2. 除了这些数据,我还有以下变量。

        1. 时间(项目添加的时间)
        2. StartsOn(项目页面开始重复的那一天)
        3. 发生(项目执行的次数)
        4. LastRun(上次执行该项目)
        5. NextRun(下次执行该项目时)
        6. 所以我不必显示未来的项目,是计划循环NextRun现在所有的项目,并且在项目执行之后将计算NextRun。 我已经尝试过了,但它似乎变得过于复杂,所以我希望那里有一个已经完成的解决方案,或者一个接近,或者只是一个提示让它走上正轨。

          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 结果,这已经过测试和工作 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Text;
          using Itenso.TimePeriod;
          
          namespace ShoppingList.Library.Objects
          {
              public class RepeatingItem
              {
                  public int? Id { get; set; }
                  public int ListId { get; set; }
                  public string Item { get; set; }
                  public int Quantity { get; set; }
                  public RepeatsType Repeats { get; set; }
                  public string RepeatsVar { get; set; }
                  public TimeSpan Time { get; set; }
                  public DateTime StartsOn { get; set; }
                  public EndsType Ends { get; set; }
                  public string EndsVar { get; set; }
                  public int Occurrences { get; set; }
                  public DateTime? LastRun { get; set; }
                  public DateTime? NextRun { get; set; }
          
                  public enum RepeatsType
                  {
                      Daily = 0,
                      Weekly = 1,
                      Monthly = 2,
                      Yearly = 3,
                  }
                  public enum EndsType
                  {
                      Never = 0,
                      After = 1,
                      On = 2
                  }
          
                  public DateTime? CalculateNextRun()
                  {
                      DateTime? next = null;
          
                      if (Repeats == RepeatsType.Daily)
                          next = HandelDailyRepeating();
                      else if (Repeats == RepeatsType.Weekly)
                          next = HandelWeeklyRepeating();
                      else if (Repeats == RepeatsType.Monthly)
                          next = HandelMonthlyRepeating();
                      else if (Repeats == RepeatsType.Yearly)
                          next = HandelYearlyRepeating();
          
                      if (Ends != EndsType.Never && next != null)
                      {
                          if (Ends == EndsType.After)
                          {
                              if (Occurrences >= int.Parse(EndsVar))
                                  next = null;
                          }
                          else if (Ends == EndsType.On)
                          {
                              if (next >= DateTime.Parse(EndsVar))
                                  next = null;
                          }
                      }
                      return next;
                  }
          
                  private DateTime? HandelDailyRepeating()
                  {
                      DateTime last;
                      // If there where a last run no problem.
                      // but we are not sure that the time on
                      // start on are right.
                      if (LastRun != null)
                          last = GetDateTime((DateTime)LastRun, Time);
                      else
                          last = GetDateTime(StartsOn, Time);
          
                      DateTime next;
                      while (last < DateTime.UtcNow || last == LastRun)
                      {
                          last = last.AddDays(1);
                      }
                      return last;
                  }
                  private DateTime? HandelWeeklyRepeating()
                  {
                      DateTime last;
                      // If there where a last run no problem.
                      // but we are not sure that the time on
                      // start on are right.
                      if (LastRun != null)
                          last = GetDateTime((DateTime)LastRun, Time);
                      else
                          last = GetDateTime(StartsOn, Time);
          
                      string[] split = RepeatsVar.Split(';');
                      int recuringInterval = int.Parse(split[0]);
                      if (recuringInterval > 52)
                          recuringInterval = 52;
          
                      DayOfWeek[] weekDays = new DayOfWeek[split.Count() - 1];
                      for (int i = 1; i < split.Count(); i++)
                      {
                          weekDays[i-1] = (DayOfWeek)int.Parse(split[i]);
                      }
          
                      int days = 0;
                      bool validFound = false;
                      while (!validFound && days <= (7 * (recuringInterval + 1)))
                      {
          
                          if (last >= DateTime.UtcNow && IsWeekRecuringDay(StartsOn, last, recuringInterval, weekDays)
                              && last != LastRun)
                          {
                              return last;
                          }
                          else
                          {
                              last = last.AddDays(1);
                              if(last > DateTime.UtcNow) days++;
                          }
                      }
                      return null;
                  }
                  private DateTime? HandelMonthlyRepeating()
                  {
                      DateTime last;
                      if (LastRun != null)
                          last = GetDateTime((DateTime)LastRun, Time);
                      else
                          last = GetDateTime(StartsOn, Time);
          
                      int recuringInterval = int.Parse(RepeatsVar);
          
                      int c = 0;
                      bool validFound = false;
                      while (!validFound && c <= (recuringInterval + 1))
                      {
                          if (last >= DateTime.UtcNow && IsMonthlyRecuringDay(StartsOn, last, recuringInterval)
                              && last != LastRun)
                          {
                              return last;
                          }
                          else
                          {
                              last = last.AddMonths(1);
                              if (last > DateTime.UtcNow) c++;
                          }
                      }
                      return null;
                  }
                  private DateTime? HandelYearlyRepeating()
                  {
                      DateTime last;
                      // If there where a last run no problem.
                      // but we are not sure that the time on
                      // start on are right.
                      if (LastRun != null)
                          last = GetDateTime((DateTime)LastRun, Time);
                      else
                          last = GetDateTime(StartsOn, Time);
          
                      int recuringInterval = int.Parse(RepeatsVar);
          
                      int c = 0;
                      bool validFound = false;
                      while (!validFound && c <= (recuringInterval + 1))
                      {
                          if (last >= DateTime.UtcNow && IsYearlyRecuringDay(StartsOn, last, recuringInterval)
                              && last != LastRun)
                          {
                              return last;
                          }
                          else
                          {
                              last = last.AddYears(1);
                              if (last > DateTime.UtcNow) c++;
                          }
                      }
                      return null;
                  }
          
                  public bool IsWeekRecuringDay(DateTime start, DateTime test, int recuringInterval, params DayOfWeek[] weekDays)
                  {
                      if (test < start || recuringInterval <= 0)
                          return false;
          
                      bool isValidDayOfWeek = false;
                      DayOfWeek testDayOfWeek = test.DayOfWeek;
          
                      // Is the given day a valid day
                      foreach (DayOfWeek weekDay in weekDays)
                      {
                          if (weekDay == testDayOfWeek)
                          {
                              isValidDayOfWeek = true;
                              break;
                          }
                      }
          
                      // If the day is not in the list, no need to go further
                      if (!isValidDayOfWeek)
                          return false;
          
                      DateDiff dateDiff = new DateDiff(GetDateTime(start, new TimeSpan(0, 0, 0)), GetDateTime(test, new TimeSpan(0, 0, 0)));
                      return (dateDiff.Weeks % recuringInterval) == 0;
                  }
                  public bool IsMonthlyRecuringDay(DateTime start, DateTime test, int recuringInterval)
                  {
                      if (test < start || recuringInterval <= 0)
                          return false;
                      DateDiff dateDiff = new DateDiff(GetDateTime(start, new TimeSpan(0, 0, 0)), GetDateTime(test, new TimeSpan(0, 0, 0)));
                      return (dateDiff.Months % recuringInterval) == 0;
                  }
                  public bool IsYearlyRecuringDay(DateTime start, DateTime test, int recuringInterval)
                  {
                      if (test < start || recuringInterval <= 0)
                          return false;
                      DateDiff dateDiff = new DateDiff(GetDateTime(start, new TimeSpan(0, 0, 0)), GetDateTime(test, new TimeSpan(0, 0, 0)));
                      return (dateDiff.Years % recuringInterval) == 0;
                  }
          
                  private DateTime GetDateTime(DateTime d, TimeSpan t)
                  {
                      return new DateTime(d.Year, d.Month, d.Day, t.Hours, t.Minutes, t.Seconds); ;
                  }
                  private TimeSpan GetTimeSpanFromDateTime(DateTime s)
                  {
                      DateTime zero = new DateTime(s.Year, s.Month, s.Day, 0, 0, 0);
                      return s - zero;
                  }
              }
          }
          

2 个答案:

答案 0 :(得分:2)

一种方法是检查测试和开始日期之间的周差异。

以下示例使用Time Period Library for .NET DateDiff 类来计算周差异:

// ----------------------------------------------------------------------
public bool IsWeekRecuringDay( DateTime start, DateTime test, int recuringInterval, params DayOfWeek[] weekDays )
{
  if ( test < start || recuringInterval <= 0 )
  {
    return false;
  }

  bool isValidDayOfWeek = false;
  DayOfWeek testDayOfWeek = test.DayOfWeek;
  foreach ( DayOfWeek weekDay in weekDays )
  {
    if ( weekDay == testDayOfWeek )
    {
      isValidDayOfWeek = true;
      break;
    }
  }
  if ( !isValidDayOfWeek )
  {
    return false;
  }

  DateDiff dateDiff = new DateDiff( start, test );
  return ( dateDiff.Weeks % recuringInterval ) == 0;
} // IsWeekRecuringDay

这里的用法:

// ----------------------------------------------------------------------
public void WeekRepeatSample()
{
  DateTime start = new DateTime( 2011, 06, 1 );
  DayOfWeek[] weekDays = new DayOfWeek[] { DayOfWeek.Monday, DayOfWeek.Thursday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday };
  Console.WriteLine( "IsWeekRecuringDay: {0}", IsWeekRecuringDay( start, new DateTime( 2011, 06, 08 ), 2, weekDays ) ); // false
  Console.WriteLine( "IsWeekRecuringDay: {0}", IsWeekRecuringDay( start, new DateTime( 2011, 06, 11 ), 2, weekDays ) ); // false
  Console.WriteLine( "IsWeekRecuringDay: {0}", IsWeekRecuringDay( start, new DateTime( 2011, 06, 15 ), 2, weekDays ) ); // true
  Console.WriteLine( "IsWeekRecuringDay: {0}", IsWeekRecuringDay( start, new DateTime( 2011, 06, 18 ), 2, weekDays ) ); // false
  Console.WriteLine( "IsWeekRecuringDay: {0}", IsWeekRecuringDay( start, new DateTime( 2011, 06, 22 ), 2, weekDays ) ); // false
  Console.WriteLine( "IsWeekRecuringDay: {0}", IsWeekRecuringDay( start, new DateTime( 2011, 06, 25 ), 2, weekDays ) ); // false
  Console.WriteLine( "IsWeekRecuringDay: {0}", IsWeekRecuringDay( start, new DateTime( 2011, 06, 29 ), 2, weekDays ) ); // true
  Console.WriteLine( "IsWeekRecuringDay: {0}", IsWeekRecuringDay( start, new DateTime( 2011, 07, 02 ), 2, weekDays ) ); // false
} // WeekRepeatSample

答案 1 :(得分:0)

您可以使用Quartz.Net作为您的计划引擎。它非常强大,可以满足您的所有日程安排需求。它支持以后在实现自己的调度程序时可能遇到的各种事情,例如例外日(假日,停电日等)。