How can I XML Serialize a DateTimeOffset Property?

Solution 1:

It's a few years late, but here's the quick and easy way to completely serialize DateTimeOffset using ISO 8601:

[XmlElement("lastUpdatedTime")]
public string lastUpdatedTimeForXml // format: 2011-11-11T15:05:46.4733406+01:00
{
   get { return lastUpdatedTime.ToString("o"); } // o = yyyy-MM-ddTHH:mm:ss.fffffffzzz
   set { lastUpdatedTime = DateTimeOffset.Parse(value); } 
}
[XmlIgnore] 
public DateTimeOffset lastUpdatedTime;

Solution 2:

I came up with this struct which implements XML serialization based on ISO 8601 formatting (e.g. 2011-11-11T15:05:46.4733406+01:00). Hint: Trying to parse a DateTime value such as 2011-11-11T15:05:46 fails as expected.

Feedback welcome. I didn't include the unit tests here because that would be too much text.

/// <remarks>
/// The default value is <c>DateTimeOffset.MinValue</c>. This is a value
/// type and has the same hash code as <c>DateTimeOffset</c>! Implicit
/// assignment from <c>DateTime</c> is neither implemented nor desirable!
/// </remarks>
public struct Iso8601SerializableDateTimeOffset : IXmlSerializable
{
    private DateTimeOffset value;

    public Iso8601SerializableDateTimeOffset(DateTimeOffset value)
    {
        this.value = value;
    }

    public static implicit operator Iso8601SerializableDateTimeOffset(DateTimeOffset value)
    {
        return new Iso8601SerializableDateTimeOffset(value);
    }

    public static implicit operator DateTimeOffset(Iso8601SerializableDateTimeOffset instance)
    {
        return instance.value;
    }

    public static bool operator ==(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b)
    {
        return a.value == b.value;
    }

    public static bool operator !=(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b)
    {
        return a.value != b.value;
    }

    public static bool operator <(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b)
    {
        return a.value < b.value;
    }

    public static bool operator >(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b)
    {
        return a.value > b.value;
    }

    public override bool Equals(object o)
    {
        if(o is Iso8601SerializableDateTimeOffset)
            return value.Equals(((Iso8601SerializableDateTimeOffset)o).value);
        else if(o is DateTimeOffset)
            return value.Equals((DateTimeOffset)o);
        else
            return false;
    }

    public override int GetHashCode()
    {
        return value.GetHashCode();
    }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        var text = reader.ReadElementString();
        value = DateTimeOffset.ParseExact(text, format: "o", formatProvider: null);
    }

    public override string ToString()
    {
        return value.ToString(format: "o");
    }

    public string ToString(string format)
    {
        return value.ToString(format);
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteString(value.ToString(format: "o"));
    }
}

Solution 3:

I'm also unsure of the best way, but here is what I did:

[XmlElement("lastUpdatedTime")]
public string lastUpdatedTimeForXml
{
  get { return lastUpdatedTime.ToString(); }
  set { lastUpdatedTime = DateTimeOffset.Parse(value); }
}
[XmlIgnore] 
public DateTimeOffset lastUpdatedTime;

Solution 4:

I have found the solution here: http://tneustaedter.blogspot.com/2012/02/proper-way-to-serialize-and-deserialize.html

Replacing XmlSerializer with DataContractSerializer works awesome. See sample code below:

    public static string XmlSerialize(this object input)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            DataContractSerializer serializer = new DataContractSerializer(input.GetType());
            serializer.WriteObject(stream, input);
            return new UTF8Encoding().GetString(stream.ToArray());
        }
    }

    public static T XmlDeserialize<T>(this string input)
    {
        using (MemoryStream memoryStream = new MemoryStream(new UTF8Encoding().GetBytes(input)))
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(T));
            return (T)serializer.ReadObject(memoryStream);
        }
    }