正在序列化UTC时间c#

本文关键字:时间 UTC 序列化 | 更新日期: 2023-09-27 18:26:13

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

正在序列化UTC时间c#

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

DTO

你没有提供DTO,所以我创建了一个作为你的原始DTO(你不能更改)和一个我们拥有的替代DTO。它们将具有相同的公共签名,只是它们的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; }
}

IDataContract代理

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);