Azure MobileServices: How to properly save DateTimeOffset with Offset

While working on Azure Mobile Service, having .Net  in both back and front end, I realized that the Offset information of a DateTimeOffset variable is lost while transfering it between client-server and viceversa.
If you look on how it is serialized in the json you’ll find something like

"2014-11-06T01:26:22.123Z"

, so… where is the offset ? well there isn’t.
This happen due to the fact that Javascript considers dates without offset and this reflects into the json serialization (json: javascript object notation).

There several work around for this. After some tries the best one that I found for my purpose is the following:

1)Define a Custom JsonConverter that handle specifically DateTimeOffset carrying also the Offset information

 

public class DateTimeOffsetConverter : JsonConverter{


        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(DateTimeOffset);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            Dictionary<string, object> temp = serializer.Deserialize<Dictionary<string, object>>(reader);
            DateTime datetime= ((DateTime)temp["datetime"]).ToUniversalTime();
            int offset = Convert.ToInt32(temp["offset"]);
            return
               new DateTimeOffset(
                  DateTime.SpecifyKind(datetime, DateTimeKind.Unspecified),
                  TimeSpan.FromMinutes(offset)
            );
        }

        
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            DateTimeOffset dto = ((DateTimeOffset)value);
            DateTime dt = dto.DateTime.Kind == DateTimeKind.Unspecified ?
               DateTime.SpecifyKind(dto.DateTime, DateTimeKind.Utc) :
               dto.DateTime.ToUniversalTime();

            Dictionary<string, object> temp = new Dictionary<string, object>
			{
				{ "datetime", dt },
				{ "offset", dto.Offset.TotalMinutes }
			};

            serializer.Serialize(writer, temp);
        }
    }

 

 

2) On azure add it as a JsonConverter of the MobileService in its registration

public static class WebApiConfig
    {
        public static void Register()
        {
            ConfigOptions options = new ConfigOptions();            
            HttpConfiguration config = ServiceConfig.Initialize(new ConfigBuilder(options));
            config.Formatters.JsonFormatter.SerializerSettings.Converters.Insert(0, new DateTimeOffsetConverter());
        }
    }

Since we inserted it as the first element of Converters list it will be asked for serialization before all the other converter which are able to convert DateTimeOffset as well (losing offsets).

3)Client side JsonConverter

In the client we have to handle DateTimeOffset as in the server in order to let them understand each others.

The JsonConverter Class is exactly the same.

In order to use such converter for ours DatTimeOffset variables we can ask to the MobileServiceClient

client.SerializerSettings.Converters.Insert (0, new DateTimeOffsetConverter ());

Doing that I had some trouble with OfflineDataSync that failed to store the variable in the localDb, actually I don’t have tried if it work without it.
What I’ve done is to annotate variables of my model as follow:

[JsonConverter(typeof(DateTimeOffsetConverter))]
DateTimeOffset myDateTimeOffset;

Is more boring since we have to annotate each variable, but is the best way that I been able to find for my purposes.

 

Note: most of the JsonConverter code has been taken somewhere on StackOverflow and modified for my purpose. Unfortunately I haven’t take note of the source, thus if you believe that you’ve written such code let me know.

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

You may also like...

3 Responses

  1. Matt Johnson says:

    Hello. Thanks for this, and I realize the post is a few years old, however there are bugs in the datetime handling. Please update as follows:

    public class DateTimeOffsetConverter : JsonConverter
    {
    public override bool CanConvert(Type objectType)
    {
    return objectType == typeof(DateTimeOffset);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
    Dictionary temp = serializer.Deserialize<Dictionary>(reader);
    DateTime datetime = (DateTime) temp[“datetime”];
    int offset = (int) temp[“offset”];
    return new DateTimeOffset(datetime).ToOffset(TimeSpan.FromMinutes(offset));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
    DateTimeOffset dto = (DateTimeOffset) value;
    Dictionary temp = new Dictionary
    {
    { “datetime”, dto.UtcDateTime },
    { “offset”, (int) dto.Offset.TotalMinutes }
    };

    serializer.Serialize(writer, temp);
    }
    }

    Thanks.

    • Michele Colombo says:

      Hi, thanks for your reply.
      As you pointed out this is few years old, indeed to be honest I can’t remember the reasons of my choices, however for what I recall this worked like a charm.. not sure if there was some weird encoding convention with the client.
      So I’ll leave your comment as a reference without editing my post since I can’t test it now.

      By the way I guess you have somewhere using Dictionary = Dictionary since unspecialized Dictionary does not exist in C#.

  2. Just wondering if this is still an issue. It seems to be what I am running into currently (March 2017).

    but thanks for this. I am going ahead and putting this to use to see if it fixes what I am seeing.

    and thanks for the updated code Matt (good to see you… online 😀 )

Leave a Reply

Your email address will not be published. Required fields are marked *