I am working on some code that deals with date ranges. I have pricing activities that have a starting-date and an end-date to set a certain price for that range. There are multiple pricing activities with intersecting date ranges.
What I ultimately need is the ability to query valid prices for a date range. I pass in (jan1,jan31) and I get back a list that says jan1–>jan10 $4 , jan11–>jan19 $3 jan20–>jan31 $4.
There are priorities between pricing activities. Some type of pricing activities have high priority, so they override other pricing activities and for certain type of pricing activities lowest price wins etc.
I currently have a class that holds these pricing activities and keeps a resolved pricing calendar. As I add new pricing activities I update the resolved calendar.
As I write more tests/code, it started to get very complicated with all the different cases (pricing activities intersecting in different ways). I am ending up with very complicated code where I am resolving a newly added pricing activity. See AddPricingActivity() method below.
Can anybody think of a simpler way to deal with this? Could there be similar code somewhere out there?
Public class PricingActivity()
{
DateTime startDate;
DateTime endDate;
Double price;
Public bool StartsBeforeEndsAfter (PricingActivity pAct)
{
// pAct covers this pricing activity
}
Public bool StartsMiddleEndsAfter (PricingActivity pAct){
// early part of pAct Itersects with later part of this pricing activity
}
//more similar methods to cover all the combinations of intersecting
}
Public Class PricingActivityList()
{
List<PricingActivity> activities;
SortedDictionary<Date, PricingActivity> resolvedPricingCalendar;
Public void AddPricingActivity(PricingActivity pAct)
{
//update the resolvedCalendar
//go over each activity and find intersecting ones
//update the resolved calendar correctly
//depending on the type of the intersection
//this part is getting out of hand…..
}
}
Some suggestions:-
Abstract DateTimeRange out of this. Do all the work of calculating overlaps, intersections and unions in a re-useable DateTimeRange class rather than here.
Don’t try to update two data structures with insert, updates and deletes – both the source information and the resolved calendar – instead update the source data and then recalculate the resolved information using a simple sweep algorithm as others have suggested. If you NEED to cache the resolved calendar between changes to the source data, do that (clear cached copy whenever source changes and recalculate) otherwise just recalculate it every time because memory not CPU is typically the bottleneck these days and optimization is something you should do only if you need it.