序列化UTC时间c#

Serializing UTC time c#

我在数据协定中有一个 DateTime 数据成员。默认情况下,datacontractserializer 将 UTC 时间序列化为 yyyy-MM-ddTHH:mm:ss.fffffffZ 格式。我需要 yyyy-MM-ddTHH:mm:ss.000Z 格式,但无法控制数据合同。那么我可以用 DataContractSerializer 做些什么,以我想要的格式提供 UTC 时间。谢谢

我创建了一个实现,它使用 IDataContractSurrogate 的实现来将您的 DTO 与您拥有的 DTO 序列化。

DTO

您没有提供 DTO,因此我创建了一个作为您的原始 DTO(您无法更改)和一个我们拥有的替代 DTO。它们将具有相同的 public 签名,只是它们的 DateTime 属性更改为 String 类型。

/// <summary>
/// original DTO, is fixed
/// </summary>
[DataContract]
class DTO
{
    [DataMember]
    public DateTime FirstDate { get; set; }

}

/// <summary>
/// Our own DTO, will act as surrogate
/// </summary>
[DataContract(Name="DTO")]
class DTO_UTC
{
    [DataMember]
    public string FirstDate { get; set; }
}

IDataContractSurrogate

IDataContractSurrogate 提供了在序列化和反序列化期间将一种类型替换为另一种类型所需的方法。

我这里使用了简单的反射。如果您需要更好的性能,请考虑在类型之间发出生成的代码,甚至生成目标类型。

public class DTOTypeSurrogate : IDataContractSurrogate
{
    // this determines how you want to replace one type with the other
    public Type GetDataContractType(Type type)
    {
        if (type == typeof(DTO))
        {
            return typeof(DTO_UTC);
        }
        return type;
    }

    public object GetDeserializedObject(object obj, Type targetType)
    {
        // do we know this type
        if (targetType == typeof(DTO))
        {
            // find each DateTime prop and copy over
            var objType = obj.GetType();
            var target = Activator.CreateInstance(targetType);
            foreach(var prop in targetType.GetProperties())
            {
                // value comes in
                var src =  objType.GetProperty(prop.Name);
                // do we need special handling
                if (prop.PropertyType == typeof(DateTime))
                {
                    DateTime utcConvert;
                    // parse to a datetime
                    if (DateTime.TryParse(
                        (string) src.GetValue(obj),
                        System.Globalization.CultureInfo.InvariantCulture, 
                        System.Globalization.DateTimeStyles.AdjustToUniversal, 
                        out utcConvert))
                    {
                        // store 
                        prop.SetValue(target, utcConvert);
                    }
                }
                else
                {
                    // store non DateTime types
                    prop.SetValue(target, src);
                }
            }
            return target;
        }
        return obj;
    }

    public object GetObjectToSerialize(object obj, Type targetType)
    {
        // go from DTO to DTO_UTC
        if (targetType == typeof(DTO_UTC))
        {
            var utcObj = Activator.CreateInstance(targetType);
            var objType = obj.GetType();
            // find our DateTime props
            foreach(var prop in objType.GetProperties())
            {
                var src = prop.GetValue(obj);
                if (prop.PropertyType == typeof(DateTime))
                {
                    // create the string
                    var dateUtc = (DateTime)src;
                    var utcString = dateUtc.ToString(
                        "yyyy-MM-ddThh:mm:ss.000Z", 
                        System.Globalization.CultureInfo.InvariantCulture);
                    // store
                    targetType.GetProperty(prop.Name).SetValue(utcObj, utcString);
                } else
                {
                    // normal copy
                    targetType.GetProperty(prop.Name).SetValue(utcObj, src);
                }
            }
            return utcObj;
        }
        // unknown types return the original obj
        return obj;
    }
   // omitted the other methods in the interfaces for brevity
}

与序列化程序一起使用

在这里我们创建了 DataContractSerializer 并为其提供了一个实例化的 DTO,在序列化之后我们反转过程以检查结果是否相同。

var surrogateSerializer =
    new DataContractSerializer(
        typeof(DTO),
        new Type[] {}, 
        Int16.MaxValue, 
        false, 
        true, 
        new DTOTypeSurrogate()); // here we provide our own implementation

var ms = new MemoryStream();
// test data
var testDto = new DTO { 
    FirstDate = new DateTime(2015, 12, 31, 4, 5, 6, DateTimeKind.Utc) };
// serialize
surrogateSerializer.WriteObject(ms, testDto);
// debug
var wireformat = Encoding.UTF8.GetString(ms.ToArray());

//reset
ms.Position = 0;
//deserialize
var dtoInstance = (DTO) surrogateSerializer.ReadObject(ms);
// verify we have the same data returned
Debug.Assert(dtoInstance.FirstDate == testDto.FirstDate);