0

Evidently when using DateTime objects in ASP.NET core, JSON.Net serializes them out with 7 digits of accuracy.

Example:

 "registrationDate": "2019-05-30T09:21:05.1676144-04:00",

or

    "registrationDate": "2019-05-30T15:34:04.0929048Z",

In Dart pad:

 var t = DateTime.parse('2019-05-30T15:34:04.0929048Z');

yields:

Uncaught exception:
FormatException: Invalid date format
2019-05-30T15:34:04.0929048Z

but when I trim the last digit (an '8'):

 var t = DateTime.parse('2019-05-30T15:34:04.092904Z');

yields:

2019-05-30 15:34:04.093Z

When consuming them in Dart from an API, Dart only accepts six digits of accuracy and throws an error when it encounters the 7th digit.

Here's the link to the Dart docs: https://api.dartlang.org/stable/2.3.1/dart-core/DateTime/parse.html

Here's the relevant code from their docs:

  int parseMilliAndMicroseconds(String matched) {
     if (matched == null) return 0;
     int length = matched.length;
     assert(length >= 1);
     assert(length <= 6);

It's unlikely there'll be a fix any time soon on the Dart side, as it's a pretty fundamental library.

So, can anyone tell me how to have my ASP.NET Core API reduce the accuracy by one digit? These dates are everywhere in the system, and it would be really great if I could just change the formatted output from one spot.

I guess an alternative would be to write a JsonConverter but I really don't want to do that for every class.

Ideas?

TIA

Bill Noel
  • 1,120
  • 9
  • 21
  • Fun! 6 digits equal to the accuracy of microseconds. 7 is an accuracy of `10s` of nanoseconds. Only tip: you can use `package:intl` to create custom DateTime formats or better yet, just send those datetimes in UTC timestamps. C# now has `DateTimeOffset.ToUnixTimeMilliseconds`. – Daniel V. May 30 '19 at 18:24
  • Thanks, although that will work, the JsonSerializer I'm using in Dart automatically generates the conversion from an ISO 8601 format. Appreciate the help. – Bill Noel May 31 '19 at 14:33
  • Sorry, the conversion is happening on the Dart side. – Bill Noel May 31 '19 at 14:40

2 Answers2

1

It seems there are two approaches, one is to use a CustomContractResolver from Json.Net. I didn't pursue that because it occurred to me that I might end up needing those seven digits for comparisons in other places that weren't restricted like Dart is.

So instead I used a JsonConverter. Here's the code:

public class DartDateTimeConverter : IsoDateTimeConverter
{
    public DartDateTimeConverter()
    {
        DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFK";
    }
}

Note the 'F' positions are only 6 long.

I took this directly from another SO example.

I then updated my data transfer object to have the related attribute:

[JsonConverter(typeof(DartDateTimeConverter))]
[JsonProperty("registrationDate")]
public DateTime RegistrationDate { get; set; }

Hope this helps someone.

Bill Noel
  • 1,120
  • 9
  • 21
0

@bill-noel's answer for attributes works very well. If this is not part of a standard model you can do it manually as shown below:

public static string GetCustomAccuracyISO8601DateString(DateTime dateTime, int accuracy = 6)
{
   accuracy = accuracy > 6 ? 6: (accuracy > 12 ? 12: accuracy);
   return dateTime.ToString($"yyyy-MM-ddTHH\\:mm\\:ss.{new String('f', accuracy)}Z", CultureInfo.InvariantCulture);
}
Kholofelo
  • 694
  • 9
  • 15