Давайте понимать, что DateTimeOffset дает вам время UTC в дополнение к тому, насколько это значение отличается от UTC. Таким образом, значение всегда однозначно идентифицирует одну точку во времени. Это очень ценная информация, которую вы, возможно, не захотите потерять. Но если из-за требований вы должны сохранить только смещение, то продолжайте читать ниже.
Поскольку у вас есть гибкость для изменения типа от DateTimeOffset до строки, возможно, вы можете немного изменить тип и использовать DateTimeOffset.
Например,
using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using Newtonsoft.Json;
namespace ConsoleApplication8
{
public struct Iso8601SerializableDateTimeOffset : IXmlSerializable
{
public 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"));
}
}
public class Foo
{
public Guid Id { get; set; }
[JsonConverter(typeof(UtcDateTimeOffsetConverter))]
public Iso8601SerializableDateTimeOffset AcquireDate { get; set; }
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo {
Id = Guid.NewGuid(),
AcquireDate = DateTimeOffset.Now
};
var xmlSerializer = new System.Xml.Serialization.XmlSerializer(foo.GetType());
xmlSerializer.Serialize(Console.Out, foo);
Console.WriteLine();
Console.ReadLine();
}
}
}
Выход
<?xml version="1.0" encoding="IBM437"?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Id>830cabe2-340b-42c6-bad4-12b5b8b1c43f</Id>
<AcquireDate>2016-03-14T10:47:51.8162249-04:00</AcquireDate>
</Foo>
Для JSON, нам нужен конвертер, но мы можем использовать Newtonsoft.Json.Converters.IsoDateTimeConverter
public class UtcDateTimeOffsetConverter : Newtonsoft.Json.Converters.IsoDateTimeConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value is Iso8601SerializableDateTimeOffset)
{
var date = (Iso8601SerializableDateTimeOffset)value;
value = date.value;
}
base.WriteJson(writer, value, serializer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object value = base.ReadJson(reader, objectType, existingValue, serializer);
if (value is Iso8601SerializableDateTimeOffset)
{
var date = (Iso8601SerializableDateTimeOffset)value;
value = date.value;
}
return value;
}
}
Контроллер
public class ValuesController : ApiController
{
public class Foo
{
public Guid Id { get; set; }
[JsonConverter(typeof(UtcDateTimeOffsetConverter))]
public Iso8601SerializableDateTimeOffset AcquireDate { get; set; }
}
// GET api/values
public IEnumerable<Foo> Get()
{
return new Foo[] {
new Foo() {
Id = Guid.NewGuid(),
AcquireDate = DateTimeOffset.Now
}
};
}
}
Выход
<ArrayOfFoo xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WebApplication1.Models">
<Foo>
<AcquireDate>2016-03-14T12:04:30.2791167-04:00</AcquireDate>
<Id>b3188528-f854-454a-bf9f-9822ff27dc6f</Id>
</Foo>
</ArrayOfFoo>
JSON
[{"Id":"e24bc769-3463-4320-b39a-9ff97e709142","AcquireDate":"2016-03-15T10:47:29.3061449-04:00"}]
Полный пример можно найти на GitHub: https://github.com/alexnolasco/DatetimeOffsetXMLSerializationExample
Смотрите также: How can I XML Serialize a DateTimeOffset Property?
Choosing Between DateTime, DateTimeOffset, TimeSpan, and TimeZoneInfo
Как бы я использовать его с Web API? Любой пример был бы полезен. –
@NileshThakkar Добавил в ответ образец метода APIController, посмотрим, поможет ли это. –
Должны ли мы внести какие-либо изменения в конфигурацию, чтобы заставить его работать в Web API? Поскольку Web API по умолчанию использует DataContractSerializer для XMLMediaTypeFormatter. –