Календарь с повторяющимися элементами - PullRequest
1 голос
/ 14 июня 2011

Здравствуйте. Я пытаюсь создать функцию, в которой пользователь может добавить элементы, которые будут повторяться с центральными интервалами. Но у меня возникли некоторые проблемы, когда я оборачиваюсь вокруг математики, поэтому я надеялся, что некоторые из вас, ребята, уже делали что-то подобное раньше.

Он основан на календаре Google, где событие может повторяться 4 разными способами.

  1. Ежедневно
  2. Еженедельные
  3. Ежемесячный
  4. Годовой

Затем пользователь определяет, какой тип повторения хочет пользователь, каждый день прост, это просто каждый день. Теперь еженедельно сложнее, так как пользователь может выбрать 2 варианта

  1. Недельный интервал (повторяется каждые две недели или третьи и т. Д.)
  2. Какой день недели (понедельник, четверг и т. Д.)

Только в месячном и годовом исчислении: 1 вариант

  1. Месяц / Годовой интервал

Помимо этих данных у меня есть следующие переменные.

  1. Время (время суток, когда элемент должен быть добавлен)
  2. StartsOn (День, когда предметный сланец начинает повторяться)
  3. Вхождение (Количество выполнений элемента)
  4. LastRun (последний раз, когда элемент был выполнен)
  5. NextRun (при следующем выполнении элемента)

Так что мне не нужно отображать будущие элементы, это план зацикливания, хотя все элементы, у которых 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 ]

2 голосов
/ 14 июня 2011

Один из подходов заключается в проверке разницы в неделях между датой тестирования и началом.

В следующем примере используется класс DateDiff библиотеки Time Period 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 голосов
/ 14 июня 2011

Вы можете использовать Quartz.Net в качестве механизма планирования. Это очень мощный и обрабатывает все ваши потребности планирования. Он поддерживает все виды вещей, с которыми вы можете столкнуться позже при реализации собственного планировщика, например, дни исключений (праздники, дни отключения и т. Д.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...