-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Description
When using DataContractSerializer with a type that contains a DateTimeOffset, that implements IXmlSerializable, and uses DataContractSerializer in the implementation of ReadXml/WriteXml, on .net7.0+
The xml looks something like this and is the same across versions.
<Container xmlns="http://schemas.datacontract.org/2004/07/">
<TestObject xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Date xmlns:d2p1="http://schemas.datacontract.org/2004/07/System">
<d2p1:DateTime>2025-04-18T02:57:13.1151301Z</d2p1:DateTime>
<d2p1:OffsetMinutes>-240</d2p1:OffsetMinutes>
</Date>
</TestObject>
</Container>
The deserialized DateTimeOffset is shifted from the true value. Something like the UTC time is interpreted as the local time, with the specified offset
Reproduction Steps
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
var testObject = new TestObject { Date = DateTimeOffset.Now };
var container = new Container { TestObject = testObject };
var dcsContainer = new DataContractSerializer(typeof(Container));
using var streamContainer = new MemoryStream();
dcsContainer.WriteObject(streamContainer, container);
streamContainer.Position = 0;
var resultContainer = dcsContainer.ReadObject(streamContainer) as Container;
Console.WriteLine(container.TestObject.Date);
Console.WriteLine(resultContainer.TestObject.Date);
Debug.Assert(container.TestObject.Date == resultContainer.TestObject.Date);
public class Container : IXmlSerializable
{
public TestObject TestObject { get; set; }
public XmlSchema? GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
var serializer = new DataContractSerializer(typeof(TestObject));
reader.ReadStartElement();
TestObject = (TestObject)serializer.ReadObject(reader);
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer)
{
var serializer = new DataContractSerializer(typeof(TestObject));
serializer.WriteObject(writer, TestObject);
}
}
[DataContract]
public class TestObject
{
[DataMember]
public DateTimeOffset Date { get; set; }
}
Expected behavior
It is expected that two lines are printed, both the same value.
Actual behavior
On net48 and net6.0, they do.
4/17/2025 10:45:00 PM -04:00
4/17/2025 10:45:00 PM -04:00
On net7.0+ the last value is shifted by the UTC offset (but still has a UTC offset, so the real time is different)
4/17/2025 10:45:00 PM -04:00
4/18/2025 2:45:00 AM -04:00
Regression?
Yes, on .net framework and .net 6.0
Known Workarounds
within the IXmlSerializable.ReadXml
implementation, use reflection to grab the InnerReader
from the passed in XmlSerializableReader reader
, and pass this inner reader to DataContractSerializer
Configuration
Windows x64
Other information
found when upgrading a CoreWCF application upgrading from .net 6 to 8