Ich arbeite an .net 4.6 in winforms (der Code stammt von der Testkonsolenanwendung)
An einem Punkt habe ich eine Liste von DateTime
und ich muss herausfinden, ob diese Liste ein bestimmtes Datum enthält oder nicht.
Dazu versuche ich Any()
in der Liste zu verwenden .____ Auch wenn die Liste das gewünschte Datum enthält, gibt Any()
nur false
zurück.
Es folgt Beispielcode, der dasselbe Verhalten aufweist. Wenn ich also eine Vorstellung von diesem Code bekommen kann, dann denke ich, dass er auch meinem echten Code helfen wird.
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");
ausgabe:
Die Ticks
und TimeOfDay
- Eigenschaften von Elementen in Ihrer dateTimeList
sind nicht gleich den Ticks
- und TimeOfDay
-Eigenschaften Ihrer dateNow
, und dateNow
weist mehr Markierungen auf als die dateTimeList
. Sie müssen diese Zeile hinzufügen:
dateNow = new DateTime(dateNow.Year, dateNow.Month,
dateNow.Day, dateNow.Hour, dateNow.Minute, 00);
Dadurch werden die Ticks
- und TimeOfDay
-Eigenschaften Ihrer dateNow
mit denen identisch, die Sie zu Ihrer dateTimeList
hinzugefügt haben.
Es gibt ein Sprichwort in der Computerprogrammierung "Auswahl ist nicht defekt". Das bedeutet, dass, wenn einige grundlegende, häufig verwendete, stark getestete Software beschädigt zu sein scheint, das Problem darin besteht, dass Sie das Problem falsch diagnostiziert haben und nicht, dass das Tool beschädigt ist.
Any
funktioniert gut.
Der Fehler ist, dass Sie das Datum an einer Stelle richtig und an der anderen Stelle falsch runden und das falsch gerundete Datum nicht dem richtig gerundeten Datum entspricht. Verwenden Sie die Ticks
-Eigenschaft an den Datumsangaben, um herauszufinden, warum eine Ihrer Rundungstechniken gut ist und eine davon völlig falsch ist.
Der Schlüssel, um herauszufinden, warum dies geschieht, ist herauszufinden, was der Unterschied zwischen den beiden DateTime
s ist, die wir vergleichen.
Wenn Sie die Ticks
-Eigenschaft der Datumszeiten ausdrucken, werden Sie Folgendes finden:
636560893800004640
636560887800000000
636560893800004640
636560888400000000
636560893800004640
636560889000000000
636560893800004640
636560889600000000
636560893800004640
636560890200000000
636560893800004640
636560890800000000
636560893800004640
636560891400000000
636560893800004640
636560892000000000
636560893800004640
636560892600000000
636560893800004640
636560893200000000
636560893800004640
636560893800000000
636560893800004640
636560894400000000
636560893800004640
636560895000000000
636560893800004640
636560895600000000
636560893800004640
636560896200000000
636560893800004640
636560896800000000
636560893800004640
636560897400000000
636560893800004640
636560898000000000
636560893800004640
636560898600000000
636560893800004640
636560899200000000
636560893800004640
636560899800000000
Wie Sie sehen können, sind diese beiden Linien wahrscheinlich die beiden DateTime
s, die Sie für gleich halten, aber nicht:
636560893800004640
636560893800000000
Das eine ist das dateNow
und das darunter ist das in der Liste.
Sieh den Unterschied? dateNow
enthält mehr Ticks als die Liste in der Liste.
Warum ist das?
Die DateTime
s in der Liste werden aus date
erstellt, das mithilfe des Konstruktors mit 6 Argumenten erstellt wird. Dadurch wird ein DateTime
so erstellt, wie Sie es angegeben haben. Dies bedeutet, dass die erstellte Instanz keine zusätzlichen Häkchen für den "Rest" enthält. Und ich kann sehen, dass Sie beim Ändern Ihres dateNow
versucht haben, alle zusätzlichen Komponenten zu entfernen, die Sie nicht interessieren, wie Sekunden und Millisekunden, aber Sie haben ticks vergessen. Wenn Sie 2 DateTime
s vergleichen, vergleichen Sie tatsächlich die Ticks.
new DateTime(1) == new DateTime(1)
true
new DateTime(1) == new DateTime(2)
false
Sie müssen also die zusätzlichen Häkchen aus Ihrem dateNow
entfernen, um das gewünschte Ergebnis zu erhalten, oder verwenden Sie einfach den Konstruktor mit 6 Argumenten.
Ihre Synchronisation mit AddSeconds
und AddMilliseconds
arbeitet mit der Genauigkeit von fff
(Millisekunden), jedoch nicht mit der Genauigkeit von Ticks
(ein Zehnmillionstel einer Sekunde). Letzteres ist für die DateTime
-Gleichheit die von Any()
verwendet wird.
Synchronisieren Sie die DateTime
-Kopie genau mit ihrem Prototyp, indem Sie diese Kopie mit dem DateTime
-KONSTRUKTOR ERSTELLEN, DER Ticks
verwendet. Dann findet Ihr Code genau das Datum mit Any()
.
Hier ist Ihr verbesserter Code als funktionierendes Fiddle .
List<DateTime> dateTimeList = new List<DateTime>();
DateTime dateNow = DateTime.Now;
// use dateNow.Ticks in the constructor to create a precise,
// synchronized DateTime clone
DateTime date = new DateTime(dateNow.Ticks);
date = date.AddMinutes(-10);
while (date < dateNow.AddMinutes(10))
{
dateTimeList.Add(date);
date = date.AddMinutes(1);
}
if (dateTimeList.Any(x => x == dateNow))
Console.WriteLine("date found");
else
Console.WriteLine("date Not found");
var format = "ddMMyyyy hh:mm:ss:fffz";
if (dateTimeList.Any(x => x.ToString(format) == dateNow.ToString(format)))
Console.WriteLine("date string matched");
else
Console.WriteLine("date string didn't match");
Wir können eine Datumszeichenfolge mit der Genauigkeit von Ticks formatieren, indem Sie anstelle von fffffff
fff
verwenden.
DateTime verwendet die System Clock, die notorisch nur auf etwa 10-15ms genau ist - wie in der Antwort auf diese Frage hervorgehoben - Holen Sie sich DateTime.Now mit Millisekunden-Genauigkeit
Um dies zu umgehen, müssen Sie Ihren Gleichheitsvergleich (==
) in Ihrer Any()
-Klausel durch eine Prüfung ersetzen, die die Ungenauigkeit berücksichtigt. Der folgende Code stimmt mit den Daten überein, wenn sie weniger als 20 ms voneinander entfernt sind ...
if (dateTimeList.Any(x => Math.Abs((dateNow - x).TotalMilliseconds) < 20)
Console.WriteLine("date found");
else
Console.WriteLine("date Not found");