Home > database >  DateTime with timezone deserialization problem
DateTime with timezone deserialization problem

Time:10-09

I am expecting in a dotnet 6 api an incoming request with JSON body, with a property that is a timestamp in ISO8601 format with timezone information, e.g. 2018-01-01T12:01:13.252 0200

My controller cannot deserialize the above value, and returns a 400 response.

If I omit the last two zeros in the timestamp, i.e. use 2018-01-01T12:01:13.252 02 everything works perfectly.

Also, if I create a GET endpoint that accepts a datetime in query string, everything works ok both with 0200 and with 02 as timezone information.

I don't understand what I am doing wrong, can anybody give a clue ?

Controller code:

public record TestRequest(DateTime Timestamp);

[HttpPost("test")]
public IActionResult TestNested([FromBody] TestRequest request)
{
    return Ok(request.Timestamp.ToUniversalTime());
}

Request sample - INVALID w/ 400 Response


curl -X 'POST' \
  'https://whatever' -H 'accept: */*' -H 'Content-Type: application/json' \
  -d '{
  "timestamp": "2022-10-08T14:45:08.890 0200"
}'

The response I am getting is

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-be3ecd4cc3611f6e7a359d59c279afc2-9b36d6d2ec59b589-00",
  "errors": {
    "request": [
      "The request field is required."
    ],
    "$.timestamp": [
      "The JSON value could not be converted to [....].TestRequest. Path: $.timestamp | LineNumber: 1 | BytePositionInLine: 45."
    ]
  }

Request sample - VALID w/ 200 Response (notice the last two zeros missing from the timezone)


curl -X 'POST' \
  'https://whatever' -H 'accept: */*' -H 'Content-Type: application/json' \
  -d '{
  "timestamp": "2022-10-08T14:45:08.890 02"
}'

CodePudding user response:

The string 2018-01-01T12:01:13.252 0200 is malformed because it is missing a : separating the hours and minutes in the offset. It should be 2018-01-01T12:01:13.252 02:00.

If you must pass it without the colon, you will need to create a custom JsonConverter to do the parsing. See this article for examples.

Also, since your data contains time zone offsets, you should probably be using DateTimeOffset rather than DateTime.


To elaborate a bit more about the format, current versions of ASP.NET Core use System.Text.Json, which expects timestamps to be in the ISO 8601-1:2019 extended profile representation. This is commonly known simply as "ISO 8601", but that specification has many different formats within it.

In ISO 8601's nomenclature the format that applies is called a "complete representation of date and time of day" (yes, it's quite verbose). There are two valid formats for such representation - "basic format" and "extended format".

  • The "basic" format omits almost all punctuation, except for the sign preceding the offset and a decimal separator for fractional seconds. (System.Text.Json doesn't use this format by default.)

    The following are both valid examples:

    20180101T120113.252 02
    20180101T120113.252 0200
    
  • By contrast, the "extended" format requires all punctuation. (This is the format System.Text.Json understands.)

    The following are both valid examples:

    2018-01-01T12:01:13.252 02
    2018-01-01T12:01:13.252 02:00
    

In both cases, the offset can be specified in terms of whole hours, or in hours and minutes. Though the spec supports both, it's reasonable to always pass the minutes, since many time zones are 30 minutes offset (and some are 45).

The ISO 8601 spec does not allow mixing the basic and extended formats. Thus one must include the : to be compliant. A similar specification for the extended format can be found in RFC 3339, which also requires the colon separator.

  • Related