I ran into interesting issue with the following requirement: Test if a process had run in the same day, if not run the process. The dates are stored as DataTimeOffset.
My original approach was to:
- Convert both values to UTC, because these dates could have been created in different time zones and have different offsets.
- View the Date value of each value. This is done after converting to UTC because the Date method ignores the offset.
Most scenarios this worked but I came across one case that the logic would fail. If one of the values had a time that was close to the previous/next day so that the when converting to UTC it would change the date. If the other value didn't have a time that also converted to the previous/next day then the date comparison failed.
So I ended up with the following logic to include that scenario:
public static bool SameDate(DateTimeOffset first, DateTimeOffset second)
{
bool returnValue = false;
DateTime firstAdjusted = first.ToUniversalTime().Date;
DateTime secondAdjusted = second.ToUniversalTime().Date;
// If date is now a day ahead after conversion, than add/deduct a day to other date if that date hasn't advanced
if (first.Date < firstAdjusted.Date && second.Date == secondAdjusted.Date)
secondAdjusted = secondAdjusted.Date.AddDays(1);
if (first.Date > firstAdjusted.Date && second.Date == secondAdjusted.Date)
secondAdjusted = secondAdjusted.Date.AddDays(-1);
if (second.Date < secondAdjusted.Date && first.Date == firstAdjusted.Date)
firstAdjusted = firstAdjusted.Date.AddDays(1);
if (second.Date > secondAdjusted.Date && first.Date == firstAdjusted.Date)
firstAdjusted = firstAdjusted.Date.AddDays(-1);
if (DateTime.Compare(firstAdjusted, secondAdjusted) == 0)
returnValue = true;
return returnValue;
}
Here is the Unit Tests that were failing that now pass:
[TestMethod()]
public void SameDateTest()
{
DateTimeOffset current = DateTimeOffset.Now;
DateTimeOffset first = current;
DateTimeOffset second = current;
// 23 hours later, next day, with negative offset (EST) -- First rolls over
first = new DateTimeOffset(2014, 1, 1, 19, 0, 0, new TimeSpan(-5, 0, 0));
second = new DateTimeOffset(2014, 1, 2, 18, 0, 0, new TimeSpan(-5, 0, 0));
Assert.IsFalse(Common.SameDate(first, second));
// 23 hours earlier, next day, with postive offset -- First rollovers
first = new DateTimeOffset(2014, 1, 1, 4, 0, 0, new TimeSpan(5, 0, 0));
second = new DateTimeOffset(2014, 1, 2, 5, 0, 0, new TimeSpan(5, 0, 0));
Assert.IsFalse(Common.SameDate(first, second));
// 23 hours later, next day, with negative offset (EST) -- Second rolls over
first = new DateTimeOffset(2014, 1, 2, 18, 0, 0, new TimeSpan(-5, 0, 0));
second = new DateTimeOffset(2014, 1, 1, 19, 0, 0, new TimeSpan(-5, 0, 0));
Assert.IsFalse(Common.SameDate(first, second));
// 23 hours earlier, next day, with postive offset -- Second rolls over
first = new DateTimeOffset(2014, 1, 2, 5, 0, 0, new TimeSpan(5, 0, 0));
second = new DateTimeOffset(2014, 1, 1, 4, 0, 0, new TimeSpan(5, 0, 0));
Assert.IsFalse(Common.SameDate(first, second));
}
My gut feeling is that there is a cleaner approach than to increment/decrement based on the other value. Is there a better approach?
The primary criteria:
- Adjust the both dates to have the same offset.
- Return true only if both first and second dates occur in the same calendar day, not within 24 hours.
Adjust the one of the dates for the difference in both dates:
In this function I am asuming that the offset will never be more than 24 hours. IE the difference between a date and it's adjusted date will not be two or more days. If this is not the case, then you can use time span comparison.