2011-06-14 60 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爲您的調度引擎。它非常強大,可以處理您的所有日程安排需求。它支持您在執行自己的日程安排時可能會遇到的各種事情,例如異常日(假期,停電日等)