I m working on .net 4.6 in winforms (here code is from test console application)
At one point I'm having a list of DateTime
and I need to figure out if this list contains specific date or not.
For that I m trying use Any()
on the list.
Even if the list does contain the desired date, Any()
returns false
only.
Following is example code, which also have same behavior. So if I can get any idea on this code, I guess it will help on my real code too.
List<DateTime> dateTimeList = new List<DateTime>();
DateTime dateNow = DateTime.Now;
DateTime date = new DateTime(dateNow.Year, dateNow.Month, dateNow.Day, dateNow.Hour, dateNow.Minute, 00);
date = date.AddMinutes(-10);
while (date < dateNow.AddMinutes(10))
{
dateTimeList.Add(date);
date = date.AddMinutes(1);
}
dateNow = dateNow.AddSeconds(-dateNow.Second);
dateNow = dateNow.AddMilliseconds(-dateNow.Millisecond);
foreach (DateTime dateInList in dateTimeList)
Console.WriteLine("date list List:" + dateInList.ToString("ddMMyyyy hh:mm:ss:fffz") + " - VS - desired date:" + dateNow.ToString("ddMMyyyy hh:mm:ss:fffz"));
if (dateTimeList.Any(x => x == dateNow))
Console.WriteLine("date found");
else
Console.WriteLine("date Not found");
if (dateTimeList.Any(x => x.ToString("ddMMyyyy hh:mm:ss:fffz") == dateNow.ToString("ddMMyyyy hh:mm:ss:fffz")))
Console.WriteLine("date string matched");
else
Console.WriteLine("date string didn't match");
output:
Problem
Your synchronization with
AddSeconds
andAddMilliseconds
works to the precision offff
(milliseconds) but not to the precision ofTicks
(one ten-millionth of a second). The latter is required for theDateTime
equality thatAny()
uses.One Solution
Precisely sync the
DateTime
copy with its prototype by creating that copy with theDateTime
constructor that takesTicks
. Then your code accurately finds the date withAny()
.Here is your improved code as a working Fiddle.
Aside
We can format a date string to the precision of ticks by using
fffffff
instead offff
.The
Ticks
andTimeOfDay
properties of items in yourdateTimeList
is not equal toTicks
andTimeOfDay
properties of yourdateNow
, anddateNow
has more ticks than the one in yourdateTimeList
. You need to add this line:This will make the
Ticks
andTimeOfDay
properties of yourdateNow
equals to ones that you've added to yourdateTimeList
.There's a saying in computer programming "select isn't broken". It means that when some basic, commonly used, heavily tested bit of software seems to be broken, the problem is that you've misdiagnosed the problem, not that the tool is broken.
Any
works just fine.The mistake is that you are rounding the date correctly in one place and incorrectly in the other, and the incorrectly rounded date is not equal to the correctly rounded date. Use the
Ticks
property on the dates to see why one of your rounding techniques is good and one of them is totally wrong.The key to finding out why this happens is finding out what's the difference between the two
DateTime
s that we are comparing.If you print out the
Ticks
property of the date times, you'll find something like this:As you can see, these two lines are likely to be the two
DateTime
s that you think would equal, but does not:The one above is the
dateNow
and the one below is the one in the list.See the difference?
dateNow
has more ticks than the one in the list.Why is this?
The
DateTime
s in the list are created fromdate
, which is created by using the constructor with 6 arguments. This creates aDateTime
just as you specified. This means that the instance created will not have any extra ticks for the "remainder". And I can see that when you change yourdateNow
, you tried to remove all the extra components that you don't care about, like seconds and milliseconds, but you forgot about ticks. When you compare 2DateTime
s you are actually comparing the ticks.So you need to remove the extra ticks from your
dateNow
to get your desired result, or just use the 6-argument constructor again.DateTime uses the System Clock which is notoriously only accurate to about 10-15ms - as highlighted in the answer to this question - Get DateTime.Now with milliseconds precision
To get round this, you'll need to replace your equality comparison (
==
) in yourAny()
clause with a check that takes account of the inaccuracy. The code below matches the dates if they are less than 20ms apart...