### Bug report
When the Grid is set up for OData-v4 binding, the columns that bind to DateOnly fields fail to filter. The date value in the filter expression contains the time portion and the following error is thrown:
"The binary operator GreaterThan is not defined for the types 'System.Nullable`1[System.DateOnly]' and 'System.Nullable`1[System.DateTimeOffset]'."
### Reproduction of the problem
1) Create a Grid that uses OData-v4 binding.
2) Bind a specified column to a DateOnly field.
3) Filter the column through the default column filter menu and open the browser DevTools to review the response of the request.
//Model
public DateOnly LastProdUpdate { get; set; }
//View
@(Html.Kendo().Grid<ProductViewModel>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(p => p.LastProdUpdate).Format("{0:dd/MM/yyyy}");
})
...
.Filterable()
.DataSource(dataSource => dataSource
.Custom()
.Type("odata-v4")
.Transport(t =>
{
t.Read(read => read.Url("/odata/Products").Data("function() {return {'$expand': 'Employee'} }"));
})
.PageSize(10)
.ServerPaging(true)
.ServerFiltering(true)
.ServerSorting(true)
)
)### Expected/desired behavior
The DateOnly fields must be filtered successfully as the DateTime fields.
### Environment
* **Kendo UI version: 2024.4.1112
* **Browser: [all]
Hello Garret,
Thank you for your feedback. It is great that you found a solution that works for you.
Regarding the synthetic property, your assumption is correct - the filtering and sorting on this property will perform after the data is retrieved from the database, which can lead to larger result sets being loaded into memory.
Regards,
Mihaela
Progress Telerik
Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.
Hi Mihaela,
Thanks for the interesting suggestion. I didn't know one could ignore and remap properties in the OData configuration. However, I presume that when filtering or sorting on the synthetic property that these will not be "passed through" to the database, meaning many more rows than necessary may be retrieved from the DB in order to perform sorting/filtering on the web server.
You wrote "Until OData natively parses $filter=CreatedAt eq 2025-07-22 as Edm.Date, this mismatch will remain a problem." Actually, this URL worked for me, where LastProdUpdate is a DateOnly column.
But this is merely academic at this point. I've long ago converted my database columns to the datetime datatype to get around this issue.
Thanks, Garrett
According to public evidence, DateOnly has no direct match in the EDM system. Meaning that it still uses Edm.DateTimeOffset as a predominant EDT Date type. OData does not recognize 2025-07-22 as a DateOnly — it parses it as DateTimeOffset. This can be verified by the filter parameter within the constructed URL:
Until OData natively parses $filter=CreatedAt eq 2025-07-22 as Edm.Date, this mismatch will remain a problem.
There are other reports that imply that there are DateOnly implications that might be interconnected with the reported problem as well:
As well as other issues that are categorized as "investigative":
The most straightforward workaround would be to introduce a synthetic property that will be serialized as a DateTimeOffset construct underneath:
For example:
public DateOnly CreatedAt
{
get;
set;
}
[NotMapped]
public DateTime CreatedAtDateTime => CreatedAt.ToDateTime(TimeOnly.MinValue);EDM Mapping (Typically in the minimal hosting model):
builder.Services.AddControllers()
.AddOData(options =>
{
options.AddRouteComponents("odata", GetEdmModel(), defaultBatchHandler);
options.Select()
.Filter()
.Count()
.OrderBy()
.Expand()
.Select()
.SetMaxTop(null);
});
...
app.UseODataBatching();
...
static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
var products = builder.EntitySet<ProductViewModel>("Products");
var productType = products.EntityType;
productType.Ignore(p => p.CreatedAt); // Ignore the DateOnly field
productType.Property(p => p.CreatedAtDateTime).Name = "CreatedAt"; // Transpose the "DateOnly" field to the synthetic property.
return builder.GetEdmModel();
}Although it will be parsed as a DateTimeOffSet construct:
<Property Name="CreatedAt" Type="Edm.DateTimeOffset" Nullable="false"/>The Grid will permit utilizing the DateOnly field as follows:
.Columns(columns =>
{
columns.Bound(p => p.CreatedAt);
})Other alternatives would inevitably require a surgical intervention within the depths of the Telerik UI for ASP.NET Core library that. More in particular, with a dedicated parsing/serialization logic aimed to convert DataSourceRequest and DataSourceResult abstractions in a more OData-friendly manner.
This is a mechanism that the Telerik UI for Blazor library is currently using.
Regards,
Mihaela
Progress Telerik
Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.