Dan Ko
Dan Ko

Reputation: 135

Microsoft.AspNetCore.Odata configure datetime serialization to use Utc or omit Timezone

I'm using Microsoft.AspNetCore.Odata 7.3 in Asp.net Web Api Core 3.1 project.

It turns out that the lib adds TimeZone of the server to DateTimes from Ef output.

Ef itself returns data with DateTimeKind.Unspecified.

So I expected the odata lib just to omit the TimeZone shift because webApi services behave this way.

The question is how to make odata not to add TimeZone of the server or return everything in utc(Z-format).

Tried to set it via NewtonSoft serializerSettings, but it doesn't work for OData endpoints

services.AddOData();

services.AddMvc(options => {options.EnableEndpointRouting = false;});

services
  .AddControllers()
  .AddNewtonsoftJson(options =>
                {
                    options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
                });

Thanks for help!

Upd: Setting DateTimeKind to Utc on Ef level(via ValueConverters) allows server to convert datetime correctly to local. But still the datetime is returned not in Z-format but with local TimeZone of server.

Upvotes: 13

Views: 3908

Answers (3)

Andrew
Andrew

Reputation: 8683

In OData v8 you can specify the timezone when configuring:

program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers().AddOData(options =>
{
    // set to use utc, and return Z instead of +00:00
    options.TimeZone = TimeZoneInfo.Utc;

    options.AddRouteComponents("odata/", ODataModel.GetEdmModel())
        .Filter()
        ...

An alternate way which seems to work is to use a DateTimeOffset on the models instead of DateTime, but that seemed too invasive.

I also added EF value converter which sets the Kind when reading from the database, but this had no effect on the output of OData.

Upvotes: 1

user21050753
user21050753

Reputation: 61

services.AddOData(options => options.TimeZone = TimeZoneInfo.Utc)

Upvotes: 4

bort
bort

Reputation: 161

I have a similar setup (also treated timestamp as UTC on EF layer) and ran into the same issue.

In my case I was able to fix it with the following extension method: https://learn.microsoft.com/en-us/previous-versions/aspnet/mt135699(v=vs.118)?redirectedfrom=MSDN

Example (Startup.cs)

 app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            if (odataRoutePrefix != null && edmModel != null)
            {
                endpoints.EnableDependencyInjection();
                endpoints.Filter().OrderBy().MaxTop(100).Count().Select();
                endpoints.MapODataRoute("odata", odataRoutePrefix, edmModel);
                endpoints.SetTimeZoneInfo(TimeZoneInfo.Utc);
            }
        });

Upvotes: 9

Related Questions