Здравствуйте. Я пытаюсь создать функцию, в которой пользователь может добавить элементы, которые будут повторяться с центральными интервалами. Но у меня возникли некоторые проблемы, когда я оборачиваюсь вокруг математики, поэтому я надеялся, что некоторые из вас, ребята, уже делали что-то подобное раньше.
Он основан на календаре Google, где событие может повторяться 4 разными способами.
- Ежедневно
- Еженедельные
- Ежемесячный
- Годовой
Затем пользователь определяет, какой тип повторения хочет пользователь, каждый день прост, это просто каждый день.
Теперь еженедельно сложнее, так как пользователь может выбрать 2 варианта
- Недельный интервал (повторяется каждые две недели или третьи и т. Д.)
- Какой день недели (понедельник, четверг и т. Д.)
Только в месячном и годовом исчислении: 1 вариант
- Месяц / Годовой интервал
Помимо этих данных у меня есть следующие переменные.
- Время (время суток, когда элемент должен быть добавлен)
- StartsOn (День, когда предметный сланец начинает повторяться)
- Вхождение (Количество выполнений элемента)
- LastRun (последний раз, когда элемент был выполнен)
- 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;
}
}
}