At first the question was not clear, now I am highlighting this part after editing because this is the problem. The second part is a complement to people better understand LINQ.
Search in a database
If the data is in a database (the question says nothing about it) the and expression will be translated to be executed in the database and depending on the provider used the DateTime.Now
will be translated into an expression that it recognizes and will run there in the database that may be with different time zone from the application. None of this is guaranteed, but it happens all the time. When you take an application variable this translation is not possible and then it compares with the fixed data of the moment it is sent to the database.
I even think this is another mistake because the schedules should all be UTC and never have a zone problem, but it’s not the focus of the question. Probably the error is modeling that adopted time zone in storage.
Another common error with LINQ
The first is using an expression that compares a data from the data collection being evaluated to the time of the moment. As time passes this moment changes. At each check of a collection element the value of Datetime.Now
changes, then in this example tends to filter a little more by having a movable value, it will narrow.
The second takes the current moment of code execution and stores it in a variable. This value is fixed, it does not change anymore. There when you go through the data collection the comparison is always being made with the same value, the value does not narrow, it does not change during the execution.
But LINQ still has a feature that further aggravates the problem. This technology uses a technique called Lazy Evaluation. When you run this line of code nothing is actually running. Only when you need the data or materialize the data collection will the execution be done. This can be done seconds, minutes or hours later in some cases. Even the time between checking one element and another can take a long time. It’s not so common, but it can happen.
Can you see how the results can be very different? One of them will always use the time of the actual execution of an element, because you used a code that tells you to take a new time each time you pass it. The other takes a time and keeps, there every time evaluating an element even though long after the time to be used is always the same, is the one who picked up right at the beginning of the execution.
I like LINQ, but I see a problem with it because people don’t understand what it is, they think there’s magic inside it and they don’t need to understand any of this "magic" stuff. Without deep understanding of LINQ I think people shouldn’t use it.
If you write these codes in your hand maybe you could understand better why this happens:
foreach (var c in Lista()) {
if (c.Validade > DateTime.Now) {
//faz alguma coisa
}
//talvez chama algo aqui demorado
}
And
var agora = DateTIme.Now;
foreach (var c in Lista()) {
if (c.Validade > agora) {
//faz alguma coisa, poderia montar uma outra lista, mas seria a materialização
}
//talvez chama algo aqui demorado
}
I put in the Github for future reference.
LINQ is not simple
And one of the problems I see most people do with LINQ is to use a ToList()
to materialize the data collection. When a person does this they probably shouldn’t use LINQ, the advantage of this technique is precisely not to materialize needlessly and if ever needed, then LINQ doesn’t help as much as it could. In case you are probably accessing the data collection without materializing for nothing and this is good, but it is also the cause of the difference.
Completion
Which gives the expected result? Go with it. I think the second is better in most cases, but I see scenario where the first is most useful. Or fix the modeling error.
As is indicated
apenas que possuem a validade da data e hora atual + 3h
the problem is the time difference between where the code is executed and the database. Try usingDatetime.UtcNow
.– tvdias
managed to verify the problem?
– tvdias
The problem was the time difference between the server that was running the code and the time of the database (the time zones were different anyway). To solve I used the 2°approach, as it filters the list with the server time (which was the right one). A 1° approach converts Datetime.Now to a select that queries the time of the database. In the case of postgres, Datetime.Now was converted to 'select current_timestamp;' Thank you for your answers!
– natielle
In this case, you can mark the answer as accepted and vote for those you found relevant. What should I do if someone answers my question?
– tvdias
Don’t forget to vote on the answers you find relevant and accept the one that solves your problem.
– tvdias