I have a large collection of automatically generated classes that are serialized to / deserialized from XML using .NET XmlSerializer. Some of those classes contain DateTime properties.
I have a requirement to serialize all DateTime properties using specific format, for example "u". :
System.DateTime.Now.ToString("u");
//returns something like "2008-06-15 21:15:07Z"
Deserialize method seems to work with this format, but serialization does not - it just gives me hardcoded format same format as I have by default in the hosting system (maybe I can trick the serializer by changing thread setting?) (check Update #1).
Note: I've already checked few related questions and they are solved by modifying original properties and adding new ones. For me it is not acceptable due to large number of modification I'd have to make.
- How to serialize Xml Date only from DateTime in C#
- Force XmlSerializer to serialize DateTime as 'YYYY-MM-DD hh:mm:ss'
Below is a sample test class that I use to test this issue.
using System;
using System.Linq;
using System.Text;
using System.Xml;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Globalization;
using System.IO;
namespace FunkyTests
{
[TestClass]
public class SerializationTests
{
[TestMethod]
public void FunkySerializationTest()
{
var date = DateTime.Now;
var dummy = new Dummy() { DummyProperty = date };
var xml = SerializeToXml(dummy);//serializes with "o" format
var expected = date.ToString("u", new CultureInfo("en-US"));//in this example I want "u" format
var actual = XDocument.Parse(xml).Descendants("DummyProperty").Single().Value;
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void FunkyDeserializationTest()
{
var date = DateTime.Now;
var dummy = new Dummy() { DummyProperty = date };
var xml = SerializeToXml(dummy);//serializes with "o" format
var deserializedDummy = DeserializeFromXml<Dummy>(xml);
Assert.AreEqual(dummy.DummyProperty, deserializedDummy.DummyProperty);
}
private static T DeserializeFromXml<T>(string xml)
{
using (var textReader = new StringReader(xml))
{
using (var reader = XmlReader.Create(textReader))
{
var serializer = new XmlSerializer(typeof(T));
var result = serializer.Deserialize(reader);
return (T)result;
}
}
}
private static string SerializeToXml<T>(T objectToSerialize)
{
var xml = new StringBuilder();
using (var writer = XmlWriter.Create(xml, new XmlWriterSettings { OmitXmlDeclaration = true }))
{
var ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
var serializer = new XmlSerializer(typeof(T));
serializer.Serialize(writer, objectToSerialize, ns);
}
return xml.ToString();
}
public class Dummy
{
public DateTime DummyProperty { get; set; }
}
}
}
Any funky ideas?
Update #1: I thought that date serialization is dependent on Thread.CurrentCulture. If I interpret XmlSerializer code correctly, format is hardcoded (thank you ILSpy).
// System.Xml.Serialization.XmlCustomFormatter
internal static string FromDateTime(DateTime value)
{
if (XmlCustomFormatter.Mode == DateTimeSerializationSection.DateTimeSerializationMode.Local)
{
return XmlConvert.ToString(value, "yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz");
}
return XmlConvert.ToString(value, XmlDateTimeSerializationMode.RoundtripKind);
}
Update #2: I have added a test method that uses proposed answer from Alexander Petrov. It fails at assertion of Ticks. According to Serialize DateTime as binary problem is in internals of DateTime and is caused by loosing "Kind" of DateTime. It was suggested to use DateTimeOffset, which leads to another problem of serialization, explained in How can I XML Serialize a DateTimeOffset Property?