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:
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
.
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.
Pour savoir pourquoi cela se produit, il est essentiel de déterminer la différence entre les deux DateTime
s 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 DateTime
s 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 DateTime
s 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 DateTime
s, 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.
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()
.
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");
Nous pouvons formater une chaîne de date avec la précision des ticks en utilisant fffffff
au lieu de fff
.
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");