Когда я десериализую строку времени с помощью XmlSerializer.Deserialize
, я ожидаю, что он будет учитывать мой местный часовой пояс, так что строка времени в формате
00:00:00.0000000+01:00
был проанализирован как 00:00, потому что я нахожусь в часовом поясе GMT + 1.
Я ошибся?
Вот код, который я запускаю для тестирования десериализации xml:
using System;
using System.IO;
using System.Xml.Serialization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Testing
{
[TestClass]
public class FooTest
{
[TestMethod]
public void Test()
{
var serializer = new XmlSerializer(typeof(Foo),
new XmlRootAttribute("Foo"));
var xml = "<Foo><TheTime>00:00:00.0000000+01:00</TheTime></Foo>";
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(xml);
writer.Flush();
stream.Position = 0;
var f = (Foo) serializer.Deserialize(stream);
Assert.AreEqual("00:00", f.TheTime.ToShortTimeString()); // actual: 01:00
}
[Serializable]
public class Foo
{
[XmlElement(DataType = "time")]
public DateTime TheTime { get; set; }
}
}
}
К сожалению, нет встроенного типа, в который можно десериализовать значение xs:time
, если оно включает смещение (которое в спецификации XSD равно по желанию).
Вместо этого вам нужно будет определить настраиваемый тип и реализовать соответствующие интерфейсы для настраиваемой сериализации и десериализации. Ниже приведена минимальная структура TimeOffset
, которая будет делать именно это.
[XmlSchemaProvider("GetSchema")]
public struct TimeOffset : IXmlSerializable
{
public DateTime Time { get; set; }
public TimeSpan Offset { get; set; }
public static XmlQualifiedName GetSchema(object xs)
{
return new XmlQualifiedName("time", "http://www.w3.org/2001/XMLSchema");
}
XmlSchema IXmlSerializable.GetSchema()
{
// this method isn't actually used, but is required to be implemented
return null;
}
void IXmlSerializable.ReadXml(XmlReader reader)
{
var s = reader.NodeType == XmlNodeType.Element
? reader.ReadElementContentAsString()
: reader.ReadContentAsString();
if (!DateTimeOffset.TryParseExact(s, "HH:mm:ss.FFFFFFFzzz",
CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto))
{
throw new FormatException("Invalid time format.");
}
this.Time = dto.DateTime;
this.Offset = dto.Offset;
}
void IXmlSerializable.WriteXml(XmlWriter writer)
{
var dto = new DateTimeOffset(this.Time, this.Offset);
writer.WriteString(dto.ToString("HH:mm:ss.FFFFFFFzzz", CultureInfo.InvariantCulture));
}
public string ToShortTimeString()
{
return this.Time.ToString("HH:mm", CultureInfo.InvariantCulture);
}
}
Определив это, теперь вы можете изменить тип Foo.TheTime
в вашем коде на TimeOffset
, и ваш тест будет пройден. Вы также можете удалить DataType = "time"
в атрибуте, поскольку он объявлен в самом объекте с помощью метода GetSchema
.