Roundtrip XML Serialization of DateTime and xsd:date?

后端 未结 2 2137
暖寄归人
暖寄归人 2021-02-13 18:17

OK, what am I missing here? MSDN says the following with regard to DateTimeSerializationMode:

In versions 2.0 and later of the .Net Framework, with this

2条回答
  •  后悔当初
    2021-02-13 19:21

    I don't see the problem you described.

    Your sample code doesn't deserialize. I added some code to deserialize, and it roundtrips as I would expect. I did not see the date move back a day, or forward a day.

    I did notice that the time portion of the d.Date field is stripped for serialization, regardless of the DateTimeKind. This seems correct to me. It doesn't make sense to me, intuitively, to either serialize a timezone with a "Date", or to convert to UTC. It would be surprising to me that if I had a Date value of 8-18-2009, and when serialized, it showed up as 8-19-2009Z. So I think the way it works now seems correct.

    • DateTime's that are serialized as xsd:dateTime include zone info.
    • DateTimes serialized as xsd:date, do not. I would also expect that with [XmlElement(DateType="time")] (xsd:time), the timezone would not be included. I didn't test this.

    So the problem as I see it is, this behavior, which makes sense to me, isn't documented clearly, especially with the changes introduced for roundtripping. The fact that DataType="date" and DataType="time" do not convert to UTC for serialization, should be clearly stated.

    you wrote:

    and any conversion to UTC will change at least the time of day,

    But I didn't see this at all. When I convert a time that is DateTimeKind.Unspecified, to Utc, it doesn't change the time of day. It just changes the kind.

    class Program
    {
        static System.IO.MemoryStream StringToMemoryStream(string s)
        {
            byte[] a = System.Text.Encoding.ASCII.GetBytes(s);
            return new System.IO.MemoryStream(a);
        }
    
    
        static void Main(string[] args)
        {
            var settings = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
            XmlSerializerNamespaces _ns = new XmlSerializerNamespaces();
            _ns.Add( "", "" );
    
            Console.WriteLine("\nDate Serialization testing...");
    
            for (int m=0; m < 2; m++)
            {
                var builder = new System.Text.StringBuilder();
    
                DateTime t = DateTime.Parse("2009-08-18T22:31:24.0019-04:00");
                DateSerTest d = new DateSerTest
                    { 
                        Date = t,
                        DateTime = t
                    };
    
                Console.WriteLine("\nRound {0}", m+1);
                if (m==1)
                    d.Date = d.Date.ToUniversalTime();
    
                Console.WriteLine("d.Date {2,-11} = {0} Kind({1})", d.Date.ToString("u"), d.Date.Kind.ToString(),
                                  (m==1) ? "(converted)" : "(original)" );
                Console.WriteLine("d.DateTime         = {0} Kind({1})", d.DateTime.ToString("u"), d.DateTime.Kind.ToString());
    
                XmlSerializer ser = new XmlSerializer(typeof(DateSerTest));
    
                Console.WriteLine("\nSerialize d");
                using ( var writer = System.Xml.XmlWriter.Create(builder, settings))
                {
                    ser.Serialize(writer, d, _ns);
                }
                string xml = builder.ToString();
                Console.WriteLine("{0}", xml);
    
                Console.WriteLine("\nDeserialize into d2");
                System.IO.MemoryStream ms = StringToMemoryStream(xml);
                DateSerTest d2= (DateSerTest) ser.Deserialize(ms);
    
                Console.WriteLine("d2.Date    = {0} Kind({1})", d2.Date.ToString("u"), d2.Date.Kind.ToString());
                Console.WriteLine("d2.DateTime= {0} Kind({1})", d2.DateTime.ToString("u"), d2.DateTime.Kind.ToString());
    
                Console.WriteLine("\nAfter SpecifyKind");
                d2.Date = DateTime.SpecifyKind(d2.Date, DateTimeKind.Utc);
                Console.WriteLine("d2.Date    = {0} Kind({1})", d2.Date.ToString("u"), d2.Date.Kind.ToString());
    
                Console.WriteLine("\nRe-Serialize d2");
                builder = new System.Text.StringBuilder();
                using ( var writer = System.Xml.XmlWriter.Create(builder, settings))
                {
                    ser.Serialize(writer, d2, _ns);
                }
                xml = builder.ToString();
                Console.WriteLine("{0}", xml);
    
            }
        }
    }
    

    The results:

    
        Date Serialization testing...
    
        Round 1
        d.Date (original)  = 2009-08-18 22:31:24Z Kind(Local)
        d.DateTime         = 2009-08-18 22:31:24Z Kind(Local)
    
        Serialize d
        
          2009-08-18
          2009-08-18T22:31:24.0019-04:00
        
    
        Deserialize into d2
        d2.Date    = 2009-08-18 00:00:00Z Kind(Unspecified)
        d2.DateTime= 2009-08-18 22:31:24Z Kind(Local)
    
        After SpecifyKind
        d2.Date    = 2009-08-18 00:00:00Z Kind(Utc)
    
        Re-Serialize d2
        
          2009-08-18
          2009-08-18T22:31:24.0019-04:00
        
    
        Round 2
        d.Date (converted) = 2009-08-19 02:31:24Z Kind(Utc)
        d.DateTime         = 2009-08-18 22:31:24Z Kind(Local)
    
        Serialize d
        
          2009-08-19
          2009-08-18T22:31:24.0019-04:00
        
    
        Deserialize into d2
        d2.Date    = 2009-08-19 00:00:00Z Kind(Unspecified)
        d2.DateTime= 2009-08-18 22:31:24Z Kind(Local)
    
        After SpecifyKind
        d2.Date    = 2009-08-19 00:00:00Z Kind(Utc)
    
        Re-Serialize d2
        
          2009-08-19
          2009-08-18T22:31:24.0019-04:00
        
    

提交回复
热议问题