Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SQLite : Datetime equality comparison not working (in memory) #9071

Closed
anna-git opened this issue Jul 5, 2017 · 21 comments
Closed

SQLite : Datetime equality comparison not working (in memory) #9071

anna-git opened this issue Jul 5, 2017 · 21 comments
Labels
closed-no-further-action The issue is closed and no further action is planned.

Comments

@anna-git
Copy link

anna-git commented Jul 5, 2017

When comparing exact dates in memory with the sqlite provider, it returns no result:

 var targets =  (from i in context.Whatever
                        where i.Date == myDate
                        select new { i.Id  }).ToList();

targets.Count is zero.
But this works and returns one item:

 var targets =  (from i in context.Whatever
                        where i.Date.CompareTo(myDate)==0
                        select new { i.Id  }).ToList();

I use Microsoft.EntityFrameworkCore.Sqlite 1.1.2.

@smitpatel
Copy link
Member

Probably the second query is being evaluated on client. There seem to be some mismatch between the format of how values being stored and how parameters are being created.

This may be fixed in latest dev due to self-contained type mapping.

@bricelam
Copy link
Contributor

bricelam commented Jul 5, 2017

Was the data inserted using EF Core? If not, it may be in an incompatible format.

@anna-git
Copy link
Author

anna-git commented Jul 5, 2017

No, the data was inserted by reading a sql script before like this:
await context.Database.ExecuteSqlCommandAsync(strCommand);

@anna-git
Copy link
Author

anna-git commented Jul 5, 2017

The date is inserted this way : '2017-08-19 00:00' . When I query the item without the equal clause on the date, and then I looked at my item specifically, the date is correctly resolved by EF in memory, the day is 19, month 8, year 2017 and the kind is unspecified.
When I compare the ticks it is working fine, like the CompareTo method, but as Smitpatel said, it might be because it is resolved in memory too..

@smitpatel
Copy link
Member

DateTime maps to TEXT in SQLite.
EF uses following format to convert date into text @"{0:yyyy\-MM\-dd HH\:mm\:ss.FFFFFFF}";
It is likely that if EF is applying any operation on datetime on server, then it would generate literal/parameter in above format. But if the stored values are in different format it will not match (text matching). Anytime the operation is done on client, it will work because we would convert text value to datetime using parse function. Since compareTo or ticks are not translated to server they work.

@anna-git
Copy link
Author

anna-git commented Jul 5, 2017

Ok, I tried setting in the sql script '2017-08-19 00:00:00.000000' but it's still not finding it when comparing through ==.. Am I doing it wrong ?

@bricelam
Copy link
Contributor

bricelam commented Jul 5, 2017

Yep, this is by design. You need to normalize coerced values (e.g. Guid, DateTime, TimeSpan, etc.) for equality comparisons to work with EF.

@bricelam
Copy link
Contributor

bricelam commented Jul 5, 2017

Hmm, manually updating the value should have worked...

@anna-git
Copy link
Author

anna-git commented Jul 6, 2017

No this is not working, I thought I missed a zero at first, but here's the new test I made to be sure:

 using (var context = new Context(options))
 {
     var date = new DateTime(2017, 08, 21, 0, 0, 0);//script.sql format : '2017-08-21 00:00:00.0000000'
     var result= context.Whatever.FirstOrDefault(w=> w.Date == date); //result null                
     var result2= context.Whatever.ToList().FirstOrDefault(w=> w.Date == date); //result2 ok
  }

Maybe I'm missing something...

@bricelam
Copy link
Contributor

bricelam commented Jul 6, 2017

Ah, .FFFFFFF won't pad with 0s. You need to specify just 2017-08-21 00:00:00 in the SQL script.

@bricelam
Copy link
Contributor

bricelam commented Jul 6, 2017

Now the question is: Do we want to switch to padding in 2.0?

The built-in SQLite function strftime('%Y-%m-%d %H:%M:%f', ...) does pad with up to three 0s. (e.g. 2017-08-21 00:00:00.000)

@bricelam
Copy link
Contributor

bricelam commented Jul 6, 2017

On the other hand, the built-in function datetime(...) doesn't use fractional seconds, so keeping it like it is probably makes the values easier to work with overall.

@anna-git
Copy link
Author

anna-git commented Jul 6, 2017

Thank you, it's working with the 2017-08-21 00:00:00 format, the == comparison retrieves the item now.

@smitpatel
Copy link
Member

@bricelam - Is there anything actionable on our side here? or should we close it as question?

@bricelam
Copy link
Contributor

bricelam commented Jul 6, 2017

I've thought about it, and I think the format we have is probably ideal. If you don't have fractional seconds, the format is compatible with datetime(). If you do, the format is lossless.

Unless someone disagrees, we can close it.

@anna-git
Copy link
Author

anna-git commented Jul 6, 2017

It's fine for me as long as I know the right format for my scripts :) many thanks to you two !!

@bricelam bricelam added the closed-no-further-action The issue is closed and no further action is planned. label Jul 6, 2017
@jjxtra
Copy link

jjxtra commented Jul 31, 2019

Why was text chosen instead of long for sqlite dates?

@bricelam
Copy link
Contributor

@jjxtra Precision and readability

@jjxtra
Copy link

jjxtra commented Jul 31, 2019

@jjxtra Precision and readability

Precision I don't get, it still takes 8 bytes for a DateTime object in memory. Converting to text converts those 8 bytes to text and does not add any precision, just wasted chars, separators, etc.

@bricelam
Copy link
Contributor

bricelam commented Aug 1, 2019

My testing in #15019 showed that milliseconds would be lost (and that was just TimeSpan, not DateTime). You are free to add a value conversion if you want:

modelBuilder.Entity<MyEntity>().Property(e => e.DateTimeProperty)
    .HasConversion(ToJulianDay, FromJulianDay);

@bricelam
Copy link
Contributor

bricelam commented Aug 1, 2019

Ah, just noticed you asked about long, not double. Answer for that: SQLite only has helper functions for working with datetime values in text and Julian day floating-point values, not long/ticks

@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-no-further-action The issue is closed and no further action is planned.
Projects
None yet
Development

No branches or pull requests

5 participants