Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Calculating which recurring events happen in a date rang
Message
From
19/06/2010 12:22:17
 
 
To
19/06/2010 11:12:18
Cetin Basoz
Engineerica Inc.
Izmir, Turkey
General information
Forum:
ASP.NET
Category:
LINQ
Miscellaneous
Thread ID:
01469538
Message ID:
01469749
Views:
25
>>>>>>>>I was going to do some ugly processing with loops, but I figured maybe Linq could help me out.
>>>>>>>>
>>>>>>>>RecurringEvents
>>>>>>>>ID (PK)
>>>>>>>>StartDate (datetime)
>>>>>>>>RecurrenceDays (int)
>>>>>>>>
>>>>>>>>How can I calculate which of these recurring events happen within a specified date range. Linq's gotta have some sexy method that will do this easily...
>>>>>>>
>>>>>>>Linq would surely have nice ways to have it but your layout seems very inadequate to me. For example what does RecurrenceDays stand for? Assuming it is the days that the event would be available continously from start:
>>>>>>>
>>>>>>>
var evList = from e in events
>>>>>>>  where e.StartDate <= end && e.StartDate.AddDays( e.RecurrenceDays ) >= start
>>>>>>>  select e;
>>>>>>>
>>>>>>>In method syntax:
>>>>>>>
>>>>>>>
var evList = events.Where( e => e.StartDate <= end && e.StartDate.AddDays( e.RecurrenceDays ) >= start);
>>>>>>>
>>>>>>>PS: You could also create extension methods in your say "ScheduleExtensions" namespace and simply use those methods for selection. It then might look like (assuming you created WithIn extension method for RecurringEvent that takes start, end parameters):
>>>>>>>
>>>>>>>
var evList = events.Where( e => e.WithIn( start, end ));
>>>>>>>
>>>>>>>Is there a setting somewhere to say that this is C# code and not VFP? Maybe class attribute or another tag?
>>>>>>>Cetin
>>>>>>
>>>>>>I'm open to a new layout, if you have a suggestion.
>>>>>
>>>>>iCalendar is the typical layout standard. I have done partial implementation in VFP and sooner or later I will need an enhanced version in C# myself:) One caveat I have seen is that also it is called a standard, it doesn't seem to be a standard and say outlook may return "unrecognized calendar format" to an icalendar format that is created by outlook:).
>>>>>Cetin
>>>>
>>>>Eh, I'm looking for something very simple. I may actually just give them a way to bulk insert dates into the db since it seems like it needs more flexibility that I originally thought.
>>>
>>>Yes that would be an option. Even though I support 'recurring' events in our application I too explicitly insert the event dates instead of recurrence definition.
>>
>>I can't say I like that approach. Seems like you'd be swapping initial simplicity for a future maintenance nightmare....
>>How far ahead do you enter dates - and how do you ensure that they *are* entered far enough ahead....
>>At what point and how often do you remove past dates?
>>What happens if someone wants to change the definition of an event (e.g. change the interval or the stop date etc......)
>
>Well that approach works because I can quickly layout the dates at runtime and at that time I know how far ahead I need (saying insert I see that I misguided, I mean insert at runtime) and sometimes I know it beforehand because say it is related with a semester and I can fill for the current semester at semester start.
>You are right of course and this one samples within that simplicity (wish it was really that simple). (Note to self: Don't forget to CC Mike:)
>
>
>void Main()
>{
>	DateTime start = new DateTime(2000,1,1);
>	DateTime end   = new DateTime(2000,2,28);
>
>	// single event
>	Console.WriteLine ("\nSingle event");
>	RecurringEvent evt = new RecurringEvent{ ID=1, StartDate=new DateTime(2000,1,15), RecurrenceDays=10 };
>	SampleWithSingleEvent(evt,start,end);
>
>	// list of events
>	Console.WriteLine ("\nList of events");
>	List<RecurringEvent> evtList =
>	new List<RecurringEvent> {
>		new RecurringEvent{ ID=1, StartDate=new DateTime(2005,1,1), RecurrenceDays=10 },
>		new RecurringEvent{ ID=2, StartDate=new DateTime(2000,1,1), RecurrenceDays=10 },
>		new RecurringEvent{ ID=3, StartDate=new DateTime(2000,1,1), RecurrenceDays=5 },
>		new RecurringEvent{ ID=4, StartDate=new DateTime(2000,1,1), RecurrenceDays=20 },
>		new RecurringEvent{ ID=5, StartDate=new DateTime(2005,1,1), RecurrenceDays=5 },
>	};
>	SampleWithEventList(evtList,start,end);
>}
>
>private static void SampleWithEventList(List<RecurringEvent> evtList, DateTime start, DateTime end)
>{
>	int days = (new int[] {(end-evtList.Min (l => l.StartDate)).Days,0}).Max();
>
>	var evtDays = from d in Enumerable.Range(0, days)
>		from e in evtList
>		let evtDate = e.StartDate.AddDays(d*e.RecurrenceDays)
>		where evtDate >= start && evtDate <= end
>		group evtDate by e into evtGroup
>		select evtGroup;  // events grouped with a list of matching dates
>	
>	var occurList = evtDays.Select (d => d.Key); // only events
>
>	bool occursBetween = (evtDays.Count() > 0);
>	if (occursBetween) {		
>		foreach (var theEventGroup in evtDays)
>		{
>			ListDates(theEventGroup.Key, theEventGroup);
>		}
>	}
>	else {
>		Console.WriteLine ("None of these events occur within given date range:");
>		foreach (var e in evtList)
>		{
>			Console.WriteLine ("\tEvent {0} with startdate {1} Recurrence Days {2}",
>				e.ID,
>				e.StartDate,
>				e.RecurrenceDays);
>		}
>   	}
>
>}
>
>private static void SampleWithSingleEvent(RecurringEvent e,DateTime start, DateTime end)
>{
>	int days = (new int[] {(end-e.StartDate).Days,0}).Max();
>
>	var evtDays = from d in Enumerable.Range(0, days)
>		let evtDate = e.StartDate.AddDays(d*e.RecurrenceDays)
>		where evtDate >= start && evtDate <= end
>		select evtDate;  // list of matching dates
>	
>	bool occursBetween = (evtDays.Count() > 0);
>	if (occursBetween) {		
>		ListDates(e, evtDays);
>	}
>	else {
>		Console.WriteLine ("Event {0} with startdate {1} Recurrence Days {2} doesn't occur within given date range.",
>			e.ID,
>			e.StartDate,
>			e.RecurrenceDays);
>   	}
>}
>
>private static void ListDates(RecurringEvent e, IEnumerable<DateTime> evtDates)
>{
>	Console.WriteLine ("Event {0} with startdate {1} Recurrence Days {2} matches date range on:",
>		e.ID,
>		e.StartDate,
>		e.RecurrenceDays);
>	foreach (var date in evtDates)
>	{
>		Console.WriteLine ("\t{0}", date);
>	}
>}
>
>public class RecurringEvent
>{
>   public int ID { get; set; }
>   public DateTime StartDate { get; set; }
>   public int RecurrenceDays { get; set; }
>}
Cetin

Hi,
Cool. But aren't you checking too many possible occurences. In SampleWithSingleEvent():
int days = (new int[] { (end - e.StartDate).Days, 0 }).Max();
//could be just?:
int days = (end - e.StartDate).Days / e.RecurrenceDays;
But still could be a lot of wasted calculations if the StartDate is way earlier than the range start ?
Update: How about:
int edays = (end - e.StartDate).Days / e.RecurrenceDays;
int sdays = (start - e.StartDate).Days / e.RecurrenceDays;
evtDays = from d in Enumerable.Range(sdays, edays-sdays+1)
              let evtDate = e.StartDate.AddDays(d * e.RecurrenceDays)
              where evtDate >= start && evtDate <= end
              select evtDate;  // list of matching dates
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform