Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does NSwag convert DateTime to DateTimeOffset in the timezone the server is in?

An application passes in DateTime values to an API where NSwag converts those to DateTimeOffset objects. The auto-generated clients have to choose DateTime or DateTimeOffset for all Datetime properties across all objects in a project. So we went with DateTimeOffset in this scenario.

If a DateTime is passed to the API, does NSwag convert to the value to the timezone the server is operating in?

In other words, does the value change based on the server location of the API?

like image 821
Dayton Rumbold Avatar asked Oct 25 '25 15:10

Dayton Rumbold


1 Answers

The behavior depends on a few different factors in the web API and consuming service, none of which are specific to NSwag per se.

For reference, let's say Service A is the ASP.NET Core API where NSwag is configured and has a model

public class Person
{
    public DateTime FavoriteDateTime { get; set; }
}

NSwag is configured to generate C# client code using DateTimeOffset for DateType and DateTimeType settings (the default) and produces a DTO like

public class Person
{
    public DateTimeOffset FavoriteDateTime { get; set; }
}

Service B consumes the NSwag-generated client code to make HTTP requests to Service A.

Short Answer

Generally speaking, yes, the value will be converted to a DateTime in the local time zone of the web server (or container) hosting the API. This applies when:

  • Service B has a C# class with a DateTimeOffset property serialized to construct an HTTP request body using the default serialization settings for the Newtonsoft.Json library and
  • Service A has a model with a DateTime property and either the Newtonsoft.Json or System.Text.Json input formatter is used with default settings to bind the model from the HTTP request body

Detailed Explanation

The exact behavior depends on the format of the string serialized into the HTTP request body from the DateTimeOffset property in Service B and the JSON body deserialization configuration in Service A.

Service B configuration

NSwag uses NJsonSchema, which has Newtonsoft.Json as the default library for JSON serialization and deserialization (reference), as opposed to System.Text.Json.

With the default Newtonsoft.Json serialization settings, a serialized HTTP request body may look like:

{
    "FavoriteDateTime": "2022-05-26T18:05:23.123-04:00"
}

However, the serialized string format may be different if the settings have been customized with a process like this:

  1. Configure NSwag with GenerateUpdateJsonSerializerSettingsMethod as false and implement a protected method UpdateJsonSerializerSettings in the class named by ClientBaseClass setting. Alternatively, set GenerateUpdateJsonSerializerSettingsMethod to true and implement the UpdateJsonSerializerSettings for each specific XyzClient class in a separate file from the generated one using a partial class. Configure CSharpClientGeneratorSettings in nswag.json.
  2. In the UpdateJsonSerializerSettings method, set JsonSerializerSettings.DateFormatString to a custom value. See JsonSerializerSettings Properties.

Since DateFormatString is used for serialization and deserialization, I don't recommend changing the DateFormatString setting for the generated client (unless you also change how Service A outputs date/time values in the HTTP response to match) but it is a setting that can impact how the value is parsed by Service A. For example, a string like "2022-05-26T22:05:23.123Z" (if the time value is in UTC) deserializes to a DateTime with a UTC value (with Kind=Utc) rather than being converted to the Service A local time zone (with DateTime.Kind=Local).

Service A configuration

ASP.NET Core input formatters, rather than NSwag, are responsible for parsing the HTTP request body to bind the C# model properties.

Two primary options for input formatters handling JSON body data are:

  1. Newtonsoft.Json (also known as Json.NET), which was the default for ASP.NET Core up through 2.2 and is still supported up through at least ASP.NET Core 6.0
  2. System.Text.Json, which became the default option starting with ASP.NET Core 3.0

With the default deserialization settings of either input formatter and Service A running on a server whose time zone is set to US Central Time, Service A will parse the request value "2022-05-26T18:05:23.123-04:00" (US Eastern Daylight Time) and bind it to Person.FavoriteDateTime as a DateTime with Kind=Local (local server time) and a time component of 17:05:23.123. Serializing this value would produce "2022-05-26T17:05:23.123-05:00" (US Central Daylight Time).

However, if the Newtonsoft.Json JsonSerializerSettings.DateTimeZoneHandling is set to Utc by configuring the options with .AddNewtonsoftJson(), then Service A will bind Person.FavoriteDateTime as a DateTime with Kind=Utc and a time part value of 22:05:23.123. Serializing this value would produce "2022-05-26T22:05:23.123+00:00" (UTC time).

It does not appear that System.Text.Json has a built-in equivalent to Newtonsoft.Json's DateTimeZoneHandling per the migration guide.

NOTE: This answer focuses on input formatters, which only handle binding the HTTP request body to a model. The behavior may be different for ASP.NET Core API action methods that bind an individual DateTime parameter from other sources than the HTTP request body (query string parameters, route data, etc.).

Recommendation

To prevent subtle bugs, you may want to avoid any timezone conversions so that your HTTP request date/time value is available verbatim in the ASP.NET Core model. To do this, consider using DateTimeOffset (rather than DateTime) for all source model properties in Service A, if feasible.

like image 71
Jonathan Lundquist Avatar answered Oct 27 '25 05:10

Jonathan Lundquist



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!