webentwicklung-frage-antwort-db.com.de

Any () - Methode in List <DateTime> funktioniert nicht wie erwartet

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:

 enter image description here

9
Amit

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.

23
S.Akbari

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.

43
Eric Lippert

Der Schlüssel, um herauszufinden, warum dies geschieht, ist herauszufinden, was der Unterschied zwischen den beiden DateTimes 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 DateTimes, 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 DateTimes 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 DateTimes 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.

10
Sweeper

Problem

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.

Eine Lösung

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");

Beiseite

Wir können eine Datumszeichenfolge mit der Genauigkeit von Ticks formatieren, indem Sie anstelle von ffffffffff verwenden.

2
Shaun Luttin

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");
0
controlbox