2011-06-14 2 views
1

Bonjour Je suis un essayant de créer une fonctionnalité où un utilisateur ajoute un élément qui sera répété sur les intervalles du centre. Mais j'ai quelques problèmes à résoudre les maths, alors j'espérais que certains d'entre vous aient déjà fait quelque chose comme ça.Calendrier avec des éléments répétitifs

Il est basé sur le calendrier Google, où un événement peut être répété par 4 méthodes différentes.

  1. Daily
  2. Hebdomadaire
  3. Mensuel
  4. annuel

Ensuite, l'utilisateur définit alors quel type de répéter l'utilisateur veut, tous les jours sont simples, il est juste chaque jour. Maintenant hebdomadaire est plus délicate, car l'utilisateur peut choisir 2 options

  1. intervalle de semaine (Répète toutes les deux semaines, ou troisième et ainsi de suite)
  2. Quel jour de la semaine (lundi, jeudi et ainsi de suite)

mensuels et annuels seulement ont 1 'option

  1. intervalle de mois/année

A côté de ces données, j'ai les variables suivantes.

  1. temps (Le temps du jour l'article sont à ajouter)
  2. StartsOn (Le jour répéter démarrer le schiste objet)
  3. Présence (Le nombre de fois que l'article a été exécuté)
  4. lastrun (la dernière fois que l'article a été exécuté)
  5. NextRun (la prochaine fois que l'article est à exécuter)

Je n'ai pas à afficher les éléments futurs, est lAPL n pour boucler si tous les éléments où le NextRun est égal à maintenant, et après que l'article a été exécuté sera le NextRun être calculé. Je me suis essayé, mais il semble devenir trop complexe, alors j'espérais qu'il y avait une solution déjà terminée, ou une solution proche, ou simplement un indice pour la mettre en place.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Le résultat, cela a été testé et fonctionne !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

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; 
     } 
    } 
} 

Répondre

2

Une approche consiste à vérifier la différence de semaine entre le test et la date de début.

L'exemple suivant utilise le la DateDiff classe du Time Period Library for .NET pour calculer les différences de semaine:

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

Et ici l'utilisation:

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

semble fonctionner très bien, l'idée est alors d'ajouter un jour à un DateTime jusqu'à ce que je frappe un vrai retour de la méthode à droite? Et la même méthode pourrait être utilisée pendant des mois et des années. Est-ce que je comprends bien? – Androme

+0

Non, il est le calcul de la différence de jours en utilisant 'DateTime.Subtract', compte tenu du début de la semaine du calendrier. Oui, vous pouvez utiliser la même approche pendant des mois et des années. – Jani

+0

Oui je sais, je juste où la pensée du code Application de l'en mon problème – Androme

0

Vous pouvez utiliser Quartz.Net comme moteur de planification . Il est très puissant et gère tous vos besoins de planification. Il prend en charge toutes sortes de choses que vous pourriez rencontrer plus tard lors de la mise en œuvre de votre propre planificateur comme les jours d'exception (congés, jours d'interdiction, etc.)

Questions connexes