Reputation: 1149
I have a system that takes information from an external source and then stores it to be displayed later.
One of the data items is a date. On the source system they have the concept of a fuzzy date i.e. not accurate to a specific day or sometimes not to a month as well. So I get dates in the format:
dd/mm/yyyy
mm/yyyy
yyyy
I can parse these to DateTime objects and work with these but when rendering later I need to be able to determine the accuracy of the date since parsing "2010" will result in a date of "01/01/2010". I want to show just the year so need to know it's original accuracy.
I've mocked up a quick class to deal with this:
public class FuzzyDate
{
public DateTime Date { get; set; }
public DateType Type { get; set; }
}
public enum DateType
{
DayMonthYear,
MonthYear,
Year
}
This will do the job for me and I can do something on the parse to handle it but I feel like this is probably quite a common problem and there is probably an existing cleaner solution.
Is there something built into .Net to do this? I had a look at the culture stuff but that didn't quite seem right.
Any help would be appreciated.
Upvotes: 27
Views: 1999
Reputation: 86778
If your data type will always handle specific periods of time (i.e. the year 1972 is a specific period of time, but the 4th of July is not specific), you can store your data as a start time and time span.
Here's a possible implementation:
public struct VagueDate
{
DateTime start, end;
public DateTime Start { get { return start; } }
public DateTime End { get { return end; } }
public TimeSpan Span { get { return end - start; } }
public VagueDate(string Date)
{
if (DateTime.TryParseExact(Date, "yyyy", null, 0, out start))
end = start.AddYears(1);
else if (DateTime.TryParseExact(Date, "MM/yyyy", null, 0, out start))
end = start.AddMonths(1);
else if (DateTime.TryParseExact(Date, "dd/MM/yyyy", null, 0, out start))
end = start.AddDays(1);
else
throw new ArgumentException("Invalid format", "Date");
}
public override string ToString()
{
return Start.ToString("dd/MM/yyyy") + " plus " + Span.TotalDays + " days";
}
}
Upvotes: 7
Reputation: 519
I think you're going down the right route. There is no concept of a 'fuzzy' date or partial date, you will need to build your own.
You will likely need more constructor methods, for example
public FuzzyDate(int year)
{
Date = new DateTime(year,1,1); // 1 Jan yy
Type = DateType.Year;
}
public FuzzyDate(int year, int month)
{
Date = new DateTime(year, month, 1); // 1 mm yy
Type = DateType.MonthYear;
}
public FuzzyDate(int year, int month, int day)
{
Date = new DateTime(year, month, day); // dd mm yy
Type = DateType.DayMonthYear;
}
Hope this helps, Kevin
Upvotes: 3
Reputation: 13167
You could create your own structure (user-defined type) based on the datetime that would allow 00 for month, and 00 for day... And then also implement icomparable, so you can do math/comparrisons on it.
http://msdn.microsoft.com/en-us/library/k69kzbs1%28v=vs.71%29.aspx
http://msdn.microsoft.com/en-us/library/system.icomparable.aspx
Upvotes: 0
Reputation: 821
As far as I am aware there is nothing built into .NET for this, the solution I'd go for is one based upon nullable values, something like this.
public class FuzzyDate
{
private int Year;
private int? Month;
private int? Day;
public FuzzyDate(int Year, int? Month, int? Day)
{
this.Year = Year;
this.Month = Month;
this.Day = Day;
}
public DateType DateType
{
get
{
if(Day.HasValue && Month.HasValue)
{
return DateType.DayMonthYear;
}
else if(Month.HasValue)
{
return DateType.MonthYear;
}
else
{
return DateType.Year;
}
}
}
public DateTime Date
{
get
{
return new DateTime(Year, Month.GetValueOrDefault(1), Day.GetValueOrDefault(1));
}
}
}
public enum DateType
{
DayMonthYear,
MonthYear,
Year
}
Upvotes: 0
Reputation: 81517
One thing I would do differently is use null-able values (or use -1 for null semantics) for month and day to indicate what data was collected. Then I would have a factory method that would take a DateType param and return a DateTime. This method would throw and exception if only the year was available and the client code tried to create a DateType.DayMonthYear.
public class FuzzyDate
{
int _year;
int? _month;
int? _day;
public DateTime Date { get; set; }
public DateType Type { get; set; }
public DateTime GetDateTime(DateType dateType) { // ...
}
public enum DateType
{
DayMonthYear,
MonthYear,
Year
}
This might seem a bit over the top but the approach would explicitly store the original data and only represent "faked" DateTime objects when requested. If you were to persist a DateTime object internally along with a DateType enum you would lose some resolution.
Upvotes: 0
Reputation: 2617
To answer your question: There is nothing built into .NET to handle this gracefully.
Your solution is as valid as any I've seen. You will probably wish to embellish your class with overrides to the ToString() method that will render your date appropriately based on the DateType.
Here are a couple other threads that attempt to address this question:
Good luck!
Upvotes: 14
Reputation: 15577
It seems to me that your approach is right. Its true that .NET DateTime support multiple formats but I guess that given that all of them are supported with a concept of steps (nanoseconds), then will be related to specific date AND time.
Upvotes: 1
Reputation: 13091
As I started to read your problem, I rapidly came to the conclusion that the answer was to implement your own FuzzyDate class. Lo and behold, that's exactly what you've done.
I can imagine that you might want to add functionality to this over time (such as comparisons that take into account the DateType).
I don't believe there's anything that will inherently help you in the .NET Framework, so I think you're doing the right thing.
Upvotes: 6