After drowning incredulous in my own frustration I finally found a solution which would not force my api consumers to cast the DateTime string in an, ugly, verbose, disturbing expression.
I also want my model to transparently look like using DateTimeOffset instead of DateTime, this will allow me in the future to refactor the database and finally use DateTimeOffset even if so far I don't need to handle time zones.
My limitation is that I cannot update my legacy database and so here is the solution.
Is this solution for you?
This solution is useful only if:
- You cannot (or want to) update your db column type (if you can you should and solve the problem)
- You use or can change you entities to use DateTimeOffset instead of DateTime (If it is a new api consider doing this to comply with odata standard and allowing you to refactor in the future the underlay database)
- You don't need to handle different time zones (this can be done but you need to work on the solution to do it)
- You use EF Core >= 2.1
Solution
- Update your entity using DateTimeOffset
public class MyEntity {
[...]
public DateTimeOffset CreatedDateTime { get; set; }
public DateTimeOffset ModifiedDateTime { get; set; }
[...]
}
- Create a ValueConverter
public static class ValueConvertes
{
public static ValueConverter<DateTimeOffset, DateTime> DateTimeToDateTimeOffset =
new ValueConverter<DateTimeOffset, DateTime>(
model => model.DateTime,
store => DateTime.SpecifyKind(store, DateTimeKind.UTC));
}
- Update your model mapping
public void Configure(EntityTypeBuilder<QuestionQML> builder)
{
builder.ToTable("MyEntityTable");
builder.Property(e => e.CreatedDateTime)
.HasColumnName("CreatedDateTime") // On DB datetime Type
.HasConversion(ValueConvertes.DateTimeToDateTimeOffset);
builder.Property(e => e.ModifiedDateTime)
.HasColumnName("ModifiedDateTime") // On DB datetime Type
.HasConversion(ValueConvertes.DateTimeToDateTimeOffset);
[...]
}
This allow you to filter in the following ways:
?$filter=CreatedDateTime gt 2010-01-25T02:13:40Z
?$filter=CreatedDateTime gt 2010-01-25T02:13:40.01234Z
?$filter=CreatedDateTime gt 2010-01-25
Special thanks to chris-clark
EDIT:
Corrected code DateTimeKind.UTC can be used when the datetime stored in the database is in UTC, if you store in a different timezone you need to set the Kind to the timezone you use, but this changes the way your datetimes will be shown in the results, showing for UK Timezone, for example, Z(GMT time) or +01:00 (BST time.
datetime2
? If you usedatetime2
, you query should work fine. – Spinoza