question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

DateTimeOffsets used to converted to local time when deserialized in v2 but what does happen in v3?

See original GitHub issue

Discussed in https://github.com/Azure/azure-cosmos-dotnet-v3/discussions/3602

<div type='discussions-op-text'>

Originally posted by vindemi December 8, 2022 Hello there,

According to this issue: DateTimeOffsets get converted to local time when deserialized I am wondering if this type of functionality takes place in the v3 version? What I mean? Right now, I am unable to write that kind of code by using v3: DocumentClient = new DocumentClient(new Uri(uri), primaryKey, new JsonSerializerSettings() { DateTimeZoneHandling = DateTimeZoneHandling.Utc }, connectionPolicy: new ConnectionPolicy { ConnectionMode = ConnectionMode.Direct, // ConnectionMode.Gateway is the default ConnectionProtocol = Protocol.Tcp })

And if this still happens in the v3 how can I resolve that issue? Or maybe right now in the v3 this is default behavior that date is serialized in UTC?</div>

How can I set UTC type of the of DateTime during serialization? Right now, it seems that this functionality is missing in V3

Issue Analytics

  • State:closed
  • Created 9 months ago
  • Comments:12 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
vindemicommented, Feb 7, 2023

Thank you @NaluTripician for detailed answer. I really appreciate it. I will close the issue due to received satisfy answer.

2reactions
NaluTripiciancommented, Feb 6, 2023

Hello,

To answer your question: "The Azure Cosmos DB .NET SDK v3 uses the built-in JSON serialization and deserialization provided by .NET. The default serialization behavior is to serialize DateTime values in the format “yyyy-MM-ddTHH:mm:ss.fffffffZ”, which is the same as UTC.": The default serialization of a DateTime object is indeed “yyyy-MM-ddTHH:mm:ss.fffffffZ”. So, if you were to have an object with a DateTime property and upload it to a Cosmos Database the value, 2/6/2023 12:18:55 PM, would become 2023-02-06T12:18:55.6097438-05:00, preserving the local time zone that the DateTime object was created in.

Circling back there is another way to add custom serialization to Cosmos in the V3 SDK. You can add a custom serializer to the CosmosClientOptions when creating the client which will be able to control all the serialization/deserialization the client does. Here is an example of how to do this.

First is creating the client:

CosmosClientOptions clientOptions = new CosmosClientOptions()
{
        Serializer = new UTCDateSerializer()
};

CosmosClient client = new(
        accountEndpoint: endpoint,
        authKeyOrResourceToken: key,
        clientOptions: clientOptions
);

Here you can see in the Serializer option I have created a new UTCDateSerializer which is a custom serializer which uses a JsonSerializer and JsonSerializerSettings which you used previously in the V2 SDK. Here is what that looks like:

public class UTCDateSerializer : CosmosSerializer
{
        private readonly JsonSerializer _serializer;
        public UTCDateSerializer()
        {    
            _serializer = new JsonSerializer
            {
                DateTimeZoneHandling = DateTimeZoneHandling.Utc
            };
        }
        public override T FromStream<T>(Stream stream)
        {
            using (stream)
            {
                if (typeof(Stream).IsAssignableFrom(typeof(T)))
                {
                    return (T)(object)(stream);
                }

                using (StreamReader sr = new StreamReader(stream))
                {
                    using (JsonTextReader jsonTextReader = new JsonTextReader(sr))
                    {
                        return _serializer.Deserialize<T>(jsonTextReader);
                    }
                }
            }
        }

        public override Stream ToStream<T>(T input)
        {
            MemoryStream streamPayload = new MemoryStream();
            using (StreamWriter streamWriter = new StreamWriter(streamPayload, encoding: Encoding.Default, bufferSize: 1024, leaveOpen: true))
            {              
                using (JsonWriter writer = new JsonTextWriter(streamWriter))
                {
                    writer.Formatting = Formatting.None;
                    _serializer.Serialize(writer, input);
                    writer.Flush();
                    streamWriter.Flush();
                }
            }

            streamPayload.Position = 0;
            return streamPayload;
        }
}

Here you can see that by adding selecting the options you want to use when creating the _serializer object we can get the same results as in the V2 SDK and use the UTC Time Zone Handling.

So, using this client with a custom serializer if we have an object with a DateTime property and upload it to Cosmos with a value of, 2/6/2023 12:22:51 PM and using a machine in the EST time zone, after serialization you could see on the Azure Portal that the value would become 2023-02-06T17:22:51.9030739Z or the equivalent time in UTC.

Next, I wanted to bring up a problem I could see coming up in your situation. This is the difference between a DateTime and a DateTimeOffset in regard to serialization. It is important to note that DateTime and DateTimeOffset preform very differently when being serialized. Even with the custom serialization option I provided above a DateTimeOffset, 2/6/2023 12:18:55 PM -5:00 will be serialized to 2023-02-06T12:18:55.6097438-05:00. This is because of the fact that DateTimeOffset represents instantiations or absolute time, not calendar or civil time. In the current version of .NET JsonSerializer will not convert a DateTimeOffset to represent UTC time because of the difference between what absolute and civil time represents. User Matt Johnson-Pint on Stack Overflow has a great explanation and guidelines of when to use DateTimeOffset over DateTime which I will link here if you are interested. But if you are still wanting to have all of your DateTime/DateTimeOffset values the first option I provided previously would be a better option.

Finally, why was the option to use JsonSerializerSettings removed from being exposed in the V3 SDK? This is because since we do not own the APIs, we are not in control of breaking changes, which could have repercussions on all customers who use that API. Additionally, the guidelines for all SDKs in Azure now state that third-party types should not be publicly exposed so all of SDKs within the umbrella of Azure will not have publicly exposed third-party types.

I hope that this answers your questions but please let me know if you have any more.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why does Json.NET DeserializeObject change ...
The obj will contain a property containing a DateTimeOffset but the value will be 2012-07-19T15:30:00+10:30 i.e. converted to the local timezone ...
Read more >
DateTimeOffset.ToLocalTime Method (System)
In performing the conversion to local time, the method first converts the current DateTimeOffset object's date and time to Coordinated Universal Time (UTC)...
Read more >
Looking for help with handling DateTime timezone problem ...
So I am trying to figure out how to serialize a RabbitMQ sent from a server in another time zone (it is 5...
Read more >
More fun with DateTime | Jon Skeet's coding blog
DateTime.Kind and conversions · ToUniversalTime: if the original kind is Local or Unspecified, convert it from local time to universal time in ...
Read more >
Why was DateTime removed from OData v4
Sanitize all inputs and convert to and from UTC; Embrace DateTimeOffset and retain the original time zone from data entry. DateTimeOffset was ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found