Implementing a "Partial Date" object
We have a requirement for a "Partial Date" object which would allow you to specify dates such as
new PartialDate(1, null, null); // first of the month
new PartialDate(1, 2, null); // first of the February
new PartialDate(null, 2, null); // February
The use case is in relation to events. For example, you might开发者_Go百科 have a course which takes place every January, in which case you don't want or need to specify the year component of the date object.
We need to be able to sort by these dates based around some arbitrary rules, hence my thought to implement a data type (which will implement IComparable<PartialDate>
, however this is outside the scope of my question).
I have a couple of Questions:
- Is this a bad idea?
- I'm working in .NET, Is there some part of the framework (or 3rd party library) which will provide this functionality?
The class itself would be fairly simple, just having three nullable integers for the date componenets. (You could even make it a structure, if you feel like reading up on how to implement a structure correctly.)
What makes it a bit complicated is handling the special cases, like:
new PartialDate(29, 2, null); // occurs only on leap years
new PartialDate(31, null, null); // occurs only seven months in a year
(Also, have a look at the parameter order year,month,day
used in the DateTime
structure, you might want to replicate that pattern instead of inventing a new one.)
An alternative to a single class could be a base class with specific implementations for seprate kinds of dates:
new MonthlyPartialDate(1); // the first every month
new YearlyParticalDate(2, 1); // the first of february
new YearlyPartialDate(2); // february
I have some concerns about the future of this project. Users have a nasty tendency of wanting more features, and there are some major gotchas in this design.
First, there is no support for weeks and week days. People will probably assume that once you have Year, Month, and Day, that Weeks and Weekdays will be simple to add. But it will not be simple at all! The interactions between the various subsets of the date components will be very complex.
Secondly, the arbitrary ordering requirement will get very complicated very quickly. How would the following be sorted?
- The year 2008.
- The second day of March.
- The first day of each month.
There is no obvious reason to put any of those before or after any of the others.
I don't see any major problems, but I'm not sure it's the best way to do it. What if something happens every Monday? You have no way to express this with your PartialDate. Other types of schedules might also be difficult.
An alternative could be to have classes like YearlySchedule, MonthlySchedule, WeeklySchedule, OneTimeSchedule, and some way to combine and exclude from them.
Another option I found from Googling is this Flexible Time Schedule which uses predicates to specify the dates.
You can take a look to the Scheduler control from DevExpress.
Anyway, in our application we didn't use it because we did need finer granularity and didn't need the calendar for UI representation. What we did is to create a basic Interval interface with a method to calculate the next date based on the last scheduler run and did create some classes for MontlyInterval, WeeklyInterval, and so on, implementing the interface.
I've used partial date as a storage mechanism:
Something like
Structure PartialDate
Public Month As Byte '0 = null
Public Day as Byte '0 = null
Public Year As Integer '0 = null (there is no 0 year)
End Structure
I never tried to define the full gamut of comparables (null year wasn't very useful).
精彩评论