views:

625

answers:

4

I have an object, it has a DateTime property... I want to pass that object from an .ashx handler back to a webpage via AJAX/JSON... I don't want to use 3rd party controls...

when I do this:

  new JavaScriptSerializer().Serialize(DateTime.Now);

I get this:

  "\/Date(1251385232334)\/"

but I want "8/26/2009" (nevermind localization... my app is very localized, so my date formatting assumptions are not up for debate in this question). If I make/register a custom converter

public class DateTimeConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new List<Type>() { typeof(DateTime), typeof(DateTime?) }; }
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        Dictionary<string, object> result = new Dictionary<string, object>();
        if (obj == null) return result;
        result["DateTime"] = ((DateTime)obj).ToShortDateString();
        return result;
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary.ContainsKey("DateTime"))
            return new DateTime(long.Parse(dictionary["DateTime"].ToString()), DateTimeKind.Unspecified);
        return null;
    }
}

then I get this result (since the return value of the custom serialize method is a dictionary):

{"DateTime":"8/27/2009"}

so now in my Javascript, instead of doing

somePerson.Birthday

I have to do

somePerson.Birthday.DateTime 

  or

somePerson.Birthday["DateTime"]

how can I make the custom converter return a direct string so that I can have clean Javascript?

A: 

link text This example works

JavaScriptSerializer serializer = new JavaScriptSerializer();

DateTime dt = DateTime.Now;
DateTime dt1 = dt;

string jsonDateNow = serializer.Serialize(dt1);
andres descalzo
that example most definitely does not work... it's exactly the same as what I listed at the top of my post... so it just outputs "\/Date(1251467694063)\/" which is not what I want. but thanks 4 the link to the other similar thread
Nick Franceschina
This example works for me perfectly, the curious thing is that if I did not create variable "dt1" serialized wrong.
andres descalzo
when you run that code, what do you get as output?
Nick Franceschina
+1  A: 

the answer is: you can't use JavaScriptConverter this way... it doesn't have the capabilities.

but for reference:

http://stackoverflow.com/questions/206384/how-to-format-json-date http://blog.stevenlevithan.com/archives/date-time-format

If you care, what I ended up doing was adding a method to the javascript string prototype to make this easier for me in code:

String.prototype.dateFromJSON = function () {
    return eval(this.replace(/\/Date\((\d+)\)\//gi, "new Date($1)"));
};

this is still painful to use in the meat of the code because you have to constantly call dateFromJSON() all over the place... which is dumb.

Nick Franceschina
+2  A: 

Actually there is an ugly way, create a JavaScriptConverter for the container (Person/Article/Whatever) class

Container:

public class Article
{
    public int Id { get; set; }
    public string Title { get; set; }
    public DateTime Date { get; set; }
}

Converter:

public class ArticleJavaScriptConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new Type[] { typeof(Article) }; }
    }

    public override object Deserialize(
        IDictionary<string, object> dictionary, 
        Type type, JavaScriptSerializer serializer)
    {
        DateTime date = 
            DateTime.ParseExact(dictionary["date"] as string, "s", null);

        return
            new Article()
            {
                Id = (int)dictionary["id"],
                Title = dictionary["title"] as string,
                Date = date
            };
    }

    public override IDictionary<string, object> Serialize(
        object obj, JavaScriptSerializer serializer)
    {
        var article = obj as Article;
        var result = new Dictionary<string,object>();

        if (article != null)
        {
            this.SerializeInternal(article, result);
        }

        return result;
    }

    private void SerializeInternal(
        Article article, IDictionary<string, object> result)
    {
        result.Add("id", article.Id);
        result.Add("title", article.Title);
        result.Add("date", article.Date.ToString("s"));
    }
}

Happily ever after...

var serializer = new JavaScriptSerializer();

serializer.RegisterConverters(
    new JavaScriptConverter[] {
        new ArticleJavaScriptConverter() 
    });

var expected = new Article()
{
    Id = 3,
    Title = "test",
    Date = DateTime.Now
};


// {"id":3,"title":"test","date":"2009-12-02T05:12:00"}
var json = serializer.Serialize(article);

var actual = serializer.Deserialize<Article>(json);

Assert.AreEqual(expected, actual);
Diadistis
A: 

I know this looks really dumb, but so far I haven't found anything better...I'm still looking though, so comments are welcome.

new JavaScriptSerializer().Serialize(DateTime.Now).Replace("\"\\/", "").Replace("\\/\"", "");

This just removes the quotes and slashes, so the output is just Date(123456789) which, though technically not a literal, is understood by the browser as an actual date value and not a string.

In JSON, it would look like this

{"myDate":Date(123456789)}

A hack, I suppose. If this is actually implemented in production code, I'd personally wrap it up, either in an extension method like FormatForDates() or wrap the serializer itself as in a decorator pattern...or in this case, an "undecorator." I must really be missing the boat as to why this seems so hard. I just want to render a date, people! :-p

StarTrekRedneck