2011-06-14 61 views
1

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

它是基于谷歌日历,其中,事件可通过4种不同的方法重复。

  1. 日报
  2. 周刊
  3. 每月

然后用户再定义什么类型的重复用户的希望,每天很简单,它只是每一天。 现在每周更加棘手,因为用户可以选择2个选项

  1. 周的时间间隔(重复每隔一周或第三等)
  2. 一周何日(星期一,四等)

每月和每年只有1个选项

  1. 月/年间隔

除此数据外,我还有以下变量。

  1. 时间(该项目被添加天的时间)
  2. StartsOn(项目页岩开始重复的那一天)
  3. 发生
  4. (次项已执行的次数) LASTRUN(上次该项目已执行)
  5. NextRun(要执行的下一次产品)

所以我没有显示未来项目,是解放军n循环所有NextRun与现在相同的项目,并且在项目执行后,将计算NextRun。 我曾尝试自己,但它似乎变得过于复杂,所以我希望能在那里有一个已经完成的解决方案在那里,或者一个接近,或者干脆只是表示正轨。

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 结果,这已经过测试并workes !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

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

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

下面的示例使用了则DateDiffTime Period Library for .NET来计算周差异:

// ---------------------------------------------------------------------- 
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 
+0

似乎工作正常,然后将一天添加到DateTime,直到我点击从方法的真正回报吧?同样的方法可以使用数月和数年。我是否理解正确? – Androme 2011-06-14 11:18:58

+0

不,它考虑日历的一周开始时使用'DateTime.Subtract'来计算天数的差异。 是的,您可以使用相同的方法数月和数年。 – Jani 2011-06-14 11:37:16

+0

是的,我知道,我只想到这个代码的实现到我的问题 – Androme 2011-06-14 11:44:59

0

您可以使用Quartz.Net为您的调度引擎。它非常强大,可以处理您的所有日程安排需求。它支持您在执行自己的日程安排时可能会遇到的各种事情,例如异常日(假期,停电日等)