DefaultSerializer.cs now uses DateTimeOffset

Recently DefaultSerializer.cs was changed to use DateTimeOffset by default while de-serializing dates. Our code and data has always been written around working with DateTime as that was the default for quite some time. While working on upgrading our SDK, we found that our dates are now deserialized improperly, which then causes them to be potentially written back improperly.

Is there a way to set the default on a bucket or cluster level in our solution? We can fix the issue by creating a new JsonSerializerSettings object with DateParseHandling = DateParseHandline.DateTime, but that would then have to be passed in on each request we make. This would be a bit of a hassle as it would be required on any call dealing with dates, and is extremely difficult to enforce across a large team of developers.

What is the suggested method to handle this issue? Why was it changed after so long? We heavily rely on the old behavior, so this is a significant change for us.

See
https://review.couchbase.org/c/couchbase-net-client/+/174399
https://issues.couchbase.com/browse/NCBC-3195

Frankly, I’m surprised the change in question had an impact, I would think if you were using the DateTime type instead of DateTimeOffset it would still work the old way.

That said, you can certainly configure it to use DateParseHandling.DateTime as the global default. Simply construct a DefaultSerializer with the desired options and pass it to ClusterOptions via the WithSerializer method. This will set the global default. You may want to refer to the baseline defaults here as a starting point: couchbase-net-client/DefaultSerializer.cs at 4047aa2e4caa8036c6d9ebe73e6f4d57b4a38986 · couchbase/couchbase-net-client · GitHub

After some more investigation into our issue I see what is happening. We have been storing our dates in the DateTime UTC format. These get written out like this: 2022-11-23T06:15:07.5583503Z. With the old default serializer, retrieving a value like that and doing ContentAs<dynamic> on it would return a DateTime object with Kind set to UTC. Calling ContentAs<JValue> and then ToObject<DateTime> would result in the UTC information being kept.

With 3.4.0, ContentAs<dynamic> now returns a DateTimeOffset object. If we do ContentAs<JValue> and then ToObject<DateTime>, we lose our UTC time zone information and now have a value that will potentially get written back to Couchbase without the time zone information.

If we use a specific type in ContentAs, for example ContentAs<MyObject> where MyObject has a DateTime property, that works fine. We should be fine to pass in the default serializer as mentioned above, and will also be a little more strict with the ContentAs call where we can. It is a bit scary to have dates start losing their time zones like we saw, but fortunately we caught it in testing.