web-dev-qa-db-fra.com

Toute méthode () sur List <DateTime> ne fonctionne pas comme prévu

Je travaille sur .net 4.6 dans Winforms (ici le code provient de l’application de la console de test)

À un moment donné, j'ai une liste de DateTime et je dois déterminer si cette liste contient une date précise ou non.

Pour cela, j’essaie d’utiliser Any() dans la liste . Même si la liste contient la date souhaitée, Any() renvoie false uniquement.

Voici un exemple de code, qui a également le même comportement. Donc, si je peux avoir une idée de ce code, je suppose que cela aidera aussi mon vrai code.

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

sortie:

 enter image description here

9
Amit

Les propriétés Ticks et TimeOfDay des éléments de votre dateTimeList ne correspondent pas aux propriétés Ticks et TimeOfDay de vos dateNow et dateNow ont plus de tics que celles de votre dateTimeList. Vous devez ajouter cette ligne:

dateNow = new DateTime(dateNow.Year, dateNow.Month,
           dateNow.Day, dateNow.Hour, dateNow.Minute, 00);

Ainsi, les propriétés Ticks et TimeOfDay de votre dateNow seront égales à celles que vous avez ajoutées à votre dateTimeList.

23
S.Akbari

Il y a un dicton en programmation informatique "select n'est pas cassé". Cela signifie que lorsque certains logiciels de base, couramment utilisés et lourdement testés, semblent rompus, le problème est que vous avez mal diagnostiqué le problème, et non que l'outil est défectueux.

Any fonctionne très bien. 

L'erreur est que vous arrondissez la date correctement à un endroit et de manière incorrecte à l'autre et que la date mal arrondie n'est pas la même. Utilisez la propriété Ticks aux dates pour voir pourquoi l’une de vos techniques d’arrondissage est bonne et l’une d’entre elles totalement fausse.

43
Eric Lippert

Pour savoir pourquoi cela se produit, il est essentiel de déterminer la différence entre les deux DateTimes que nous comparons.

Si vous imprimez la propriété Ticks de la date/heure, vous obtiendrez quelque chose comme ceci:

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

Comme vous pouvez le constater, ces deux lignes sont probablement les deux DateTimes que vous pensez égales, mais ne:

636560893800004640
636560893800000000

Celui ci-dessus est la dateNow et celui ci-dessous est celui de la liste.

Regarde la différence? dateNow a plus de ticks que celui de la liste.

Pourquoi est-ce?

Les DateTimes de la liste sont créés à partir de date, créé à l’aide du constructeur avec 6 arguments. Cela crée une DateTime exactement comme vous l'avez spécifié. Cela signifie que l'instance créée n'aura pas de ticks supplémentaires pour le "reste". Et je peux voir que lorsque vous changez votre dateNow, vous avez essayé de supprimer tous les composants supplémentaires qui vous importent le plus, comme les secondes et les millisecondes, mais vous avez oublié ticks. Lorsque vous comparez 2 DateTimes, vous comparez les ticks.

new DateTime(1) == new DateTime(1)
true
new DateTime(1) == new DateTime(2)
false

Vous devez donc supprimer les ticks supplémentaires de votre dateNow pour obtenir le résultat souhaité ou simplement utiliser à nouveau le constructeur à 6 arguments.

10
Sweeper

Problème

Votre synchronisation avec AddSeconds et AddMilliseconds fonctionne avec la précision de fff (millisecondes) mais pas avec la précision de Ticks (un dix millionième de seconde). Ce dernier est requis pour l'égalité DateTime utilisée par Any().

Une solution

Synchronisez précisément la copie DateTime avec son prototype en créant cette copie avec le constructeur DateTime QUI PREND Ticks . Ensuite, votre code trouve précisément la date avec Any()

Ici est votre code amélioré en tant que Fiddle de travail.

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

De côté

Nous pouvons formater une chaîne de date avec la précision des ticks en utilisant fffffff au lieu de fff.

2
Shaun Luttin

DateTime utilise la System Clock, qui est notoirement précise à environ 10-15ms - comme indiqué dans la réponse à cette question - Obtenez DateTime.Now avec une précision de quelques millisecondes

Pour contourner ce problème, vous devez remplacer votre comparaison d'égalité (==) dans votre clause Any() par un contrôle qui prend en compte l'inexactitude. Le code ci-dessous correspond aux dates si elles sont séparées de moins de 20ms ...

if (dateTimeList.Any(x => Math.Abs((dateNow - x).TotalMilliseconds) < 20)
    Console.WriteLine("date found");
else
    Console.WriteLine("date Not found");
0
controlbox