-3

In my ASP.NET web service I need all my dates to be serialized to JSON as numbers which represent a number of milliseconds passed since 1970 please. I'm using Newtonsoft.Json serializer. What do I need to do to set it up this way?

UPDATE: the available documentation (http://www.newtonsoft.com/json/help/html/DatesInJSON.htm) only mentions serializing a single object with custom settings, what i am looking for is the default serialization settings that would govern serialization of any object

Bugs
  • 4,491
  • 9
  • 32
  • 41
Trident D'Gao
  • 18,973
  • 19
  • 95
  • 159
  • Before someone answers, did you look at the [relevant documentation](http://www.newtonsoft.com/json/help/html/DatesInJSON.htm)? It makes mention there of several different converters and it's hinted that you could implement your own. – mason Jul 06 '17 at 18:36
  • Is this Web API? ASMX? WCF? MVC? – mason Jul 06 '17 at 18:52
  • @mason it's ASP.NET – Trident D'Gao Jul 06 '17 at 18:52
  • Web API, ASMX, WCF, and MVC are all part of ASP.NET. Which specifically are you using? How you specify default settings is different depending on what framework you're using. – mason Jul 06 '17 at 18:55
  • i think it's web API, although i am not sure, do you know how to find out? – Trident D'Gao Jul 06 '17 at 18:57
  • Look at your controllers. Do they inherit from System.Web.Mvc.Controller? Or from System.Web.Http.ApiController? – mason Jul 06 '17 at 18:58
  • it's `ApiController` – Trident D'Gao Jul 06 '17 at 19:01
  • Look at the [Web API documentation](https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/json-and-xml-serialization#json_dates). You can set it to use Microsoft JSON Date Format. – mason Jul 06 '17 at 19:02
  • it doesn't work because there are only 2 customizable options: 1. enum: either iso date or ms-json date, 2. datestringformat (which cannot be used to get total number of milliseconds) – Trident D'Gao Jul 06 '17 at 20:14

4 Answers4

0

Off the top of my head I would get the ticks of the 1970 date subtract it from the ticks of the current date then divide by 10000 since there are 10000 ticks in a milisecond. This will give you a number which should be easier to serialize. You could make this an extension method of DateTime. Ticks on MSDN: DateTime.Ticks

Lucas F.
  • 33
  • 5
  • The other option is use a TimeSpan and use TotalMilliseconds. – Lucas F. Jul 06 '17 at 20:47
  • Looking back at your original question I have the answer for how to do the date math, but your specific question is for default serialization of DateTime. So you can probably ignore these. – Lucas F. Jul 06 '17 at 21:00
  • its not about date math, its about customixing the asp.net serializer to yeild numbers of toal milliseconds since 1970 instead of an iso date strings for DateTime values – Trident D'Gao Jul 06 '17 at 21:03
0

Have a look at this excellent blog post on creating your own DateTime converter to deal with your requirement. Example actually shows you creating UnixDateTimeConverter.

kebin
  • 163
  • 5
  • so you want me to annotate every single date time property with an attribute? thats way too much work – Trident D'Gao Jul 06 '17 at 21:05
  • You are not forced to use attributes, instead you can use IContractResolver to do this automatically. Look at the [official documentation](http://www.newtonsoft.com/json/help/html/ContractResolver.htm#CustomIContractResolverExamples) of how this can be achieved. – kebin Jul 06 '17 at 21:52
0

I'm not sure if this is the easiest way, but you can create a custom converter for DateTimes, then a custom JsonMediaTypeFormatter which uses that converter.

// This class overrides conversion for DateTime values
public class MyDateConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DateTime);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // Your algorithm here
        var customValue = ((DateTime)value).Ticks;
        writer.WriteValue(customValue);
    }
}

// This formatter will create serializers with the above converter injected
public class MyJsonFormatter : JsonMediaTypeFormatter
{
    public override JsonSerializer CreateJsonSerializer()
    {
        var serializer = base.CreateJsonSerializer();
        serializer.Converters.Add(new MyDateConverter());
        return serializer;
    }
}

// Inside your WebApi config code, replace the default formatter with your custom one
var defaultJsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
config.Formatters.Remove(defaultJsonFormatter);
config.Formatters.Insert(0, new MyJsonFormatter());
Misko
  • 2,044
  • 12
  • 15
0

here is what worked:

public class MyConverter: JsonConverter
{
    public override bool CanConvert(Type type)
    {
        return (type == typeof(DateTime) || type == typeof(DateTime?));
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return new NotSupportedException("An attempt to read a date using a write-only converter from DateTime -> number of milliseconds since 1970.");
    }

    static readonly long ticksTo1970 = new DateTime(1970, 1, 1).Ticks;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value is DateTime)
        {
            var date = (DateTime)value;
            var unixDateSpan = new TimeSpan(date.Ticks - ticksTo1970);
            var milliseconds = (long)unixDateSpan.TotalMilliseconds;
            writer.WriteValue(milliseconds);
        }
        else
        {
            throw new NotSupportedException("A value of unexpected type where a DateTime value is expected.");
        }
    }
}

public class BaseApiController : ApiController
{
    [NonAction]
    protected JsonResult<T> MyJson<T>(T data)
    {
        var result = this.Json(data);
        result.SerializerSettings.Converters.Insert(0, new MyConverter());
        return result;
    }   
}
hastrb
  • 410
  • 4
  • 12
Trident D'Gao
  • 18,973
  • 19
  • 95
  • 159