【问题标题】:How to serialize to dateTime如何序列化为 dateTime
【发布时间】:2008-11-21 00:45:07
【问题描述】:

努力获取任何时区的日期时间。 我正在使用 DateTimeOffset、一个字符串和一个 XmlElement 属性。当我这样做时,我收到以下错误:

[InvalidOperationException: 'dateTime' 是无效的值 XmlElementAttribute.DataType 属性。 dateTime 无法转换为 System.String.]
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel 模型,字符串 ns,ImportContext 上下文,字符串数据类型, XmlAttributes a,布尔重复, 布尔型 openModel、RecursionLimiter 限制器)+450

[InvalidOperationException:有 错误反映类型 'System.String'。]
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel 模型,字符串 ns,ImportContext 上下文,字符串数据类型, XmlAttributes a,布尔重复, 布尔型 openModel、RecursionLimiter 限制器)+1621
System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(成员映射 访问器,FieldModel 模型, XmlAttributes a, String ns, Type 选择标识符类型,布尔 rpc, 布尔型 openModel、RecursionLimiter 限制器)+8750
System.Xml.Serialization.XmlReflectionImporter.ImportFieldMapping(StructModel 父级,FieldModel 模型, XmlAttributes a, String ns, RecursionLimiter 限制器)+139
System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(结构映射 映射,StructModel 模型,布尔值 openModel,字符串类型名称, RecursionLimiter 限制器)+1273

[InvalidOperationException:有 反映属性的错误 'creationTimeX'。] ...

代码:

 [System.Xml.Serialization.XmlElement(ElementName = "creationTime",
      DataType="dateTime")]
 public string creationTimeX
    {
        get
        {
            return this.creationTimeField.ToString("yyyy-MM-ddTHH:mm:sszzz");
        }
        set
        {
            DateTimeOffset.TryParse(value, out this.creationTimeField);
        }
    }

[System.Xml.Serialization.XmlIgnoreAttribute()]
public System.DateTimeOffset creationTime
{
    get {
        return this.creationTimeField;
    }
    set {
        this.creationTimeField = value;
    }
}

【问题讨论】:

  • 仅作记录。当心DateTimeOffset。使用 WCF 序列化时,序列化 DateTimeOffset 时出现一些问题。

标签: c# datetime .net-2.0 xml-serialization


【解决方案1】:

这对我有用

private const string DateTimeOffsetFormatString = "yyyy-MM-ddTHH:mm:sszzz";
private DateTimeOffset eventTimeField;

[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public string eventTime
{
    get { return eventTimeField.ToString(DateTimeOffsetFormatString); }
    set { eventTimeField = DateTimeOffset.Parse(value); }
}

【讨论】:

    【解决方案2】:

    看看这个关于序列化日期和 UTC 的 StackOverflow 问题:

    Best practices for DateTime serialization in .Net framework 3.5/SQL Server 2008

    不需要创建一个特殊的属性来完成序列化。

    【讨论】:

    • 评论说明了一切......即使 ISO 时间允许任何事情......如果你绝对,肯定必须知道时区本身(即上述可能是东部标准时间或中部夏令时间),你需要创建自己的数据类型来公开这些部分。实现 iXmlSerializer
    • UTC 是旧方法(确保序列化),但没有回答有关序列化 DateTimeOffset 的问题(与时区相关)。阅读有关该主题的 MSDN 文章,Microsoft 的当前建议是 DateTimeOffset 用于处理/存储,TimeZoneInfo 用于任何涉及时区的计算:msdn.microsoft.com/en-us/library/bb384267(v=vs.110).aspx 只有选项是使用不同的序列化程序(DataContract 或 NetDataContract),添加类似解决方法的属性我添加到 MS 连接文章中,或者使用 UTC 和时区 ID 创建自己的结构,但这不太标准
    【解决方案3】:

    使用 XmlConvert.ToDateTimeOffset() 和 .ToString() 方法在 XmlSerializer 变通方法属性中正确序列化和反序列化 DateTimeOffset。

    此处的 Microsoft Connect 文章中的完整示例,并确认不幸的是 Microsoft 不会修复此疏忽(XmlSerializer 应该本机支持它作为任何原始类型):

    https://connect.microsoft.com/VisualStudio/feedback/details/288349/datetimeoffset-is-not-serialized-by-a-xmlserializer

    【讨论】:

      【解决方案4】:

      我建议您将 DateTime 序列化为 long(这是实现在内部用于存储实际值的内容)。

      您可以使用DateTime.Ticks 来获取值,它有一个需要很长时间的构造函数 (Int64)。

      【讨论】:

      【解决方案5】:

      这是 2019 年,我从这个 gist 找到了一个很棒的自定义类型和属性抽屉 UDateTime 的单个脚本

      using System;
      #if UNITY_EDITOR
      using UnityEditor;
      #endif
      using UnityEngine;
      
      // we have to use UDateTime instead of DateTime on our classes
      // we still typically need to either cast this to a DateTime or read the DateTime field directly
      [System.Serializable]
      public class UDateTime : ISerializationCallbackReceiver {
          [HideInInspector] public DateTime dateTime;
      
          // if you don't want to use the PropertyDrawer then remove HideInInspector here
          [HideInInspector] [SerializeField] private string _dateTime;
      
          public static implicit operator DateTime(UDateTime udt) {
              return (udt.dateTime);
          }
      
          public static implicit operator UDateTime(DateTime dt) {
              return new UDateTime() {dateTime = dt};
          }
      
          public void OnAfterDeserialize() {
              DateTime.TryParse(_dateTime, out dateTime);
          }
      
          public void OnBeforeSerialize() {
              _dateTime = dateTime.ToString();
          }
      }
      
      // if we implement this PropertyDrawer then we keep the label next to the text field
      #if UNITY_EDITOR
      [CustomPropertyDrawer(typeof(UDateTime))]
      public class UDateTimeDrawer : PropertyDrawer {
          // Draw the property inside the given rect
          public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
              // Using BeginProperty / EndProperty on the parent property means that
              // prefab override logic works on the entire property.
              EditorGUI.BeginProperty(position, label, property);
      
              // Draw label
              position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
      
              // Don't make child fields be indented
              var indent = EditorGUI.indentLevel;
              EditorGUI.indentLevel = 0;
      
              // Calculate rects
              Rect amountRect = new Rect(position.x, position.y, position.width, position.height);
      
              // Draw fields - passs GUIContent.none to each so they are drawn without labels
              EditorGUI.PropertyField(amountRect, property.FindPropertyRelative("_dateTime"), GUIContent.none);
      
              // Set indent back to what it was
              EditorGUI.indentLevel = indent;
      
              EditorGUI.EndProperty();
          }
      }
      #endif
      

      【讨论】:

        【解决方案6】:

        属性creationTimeX 的数据类型是字符串,而XmlSerialization 数据类型是DateTime。这就是为什么您会遇到该异常。

        您可以通过将数据类型更改为 DateTime 来解决此问题。

        此外,对于任何时区的当前时间问题,您必须应用 DateTime.Now.ToUniveralTime() 并在其上应用适当的 DateTimeFormat 模式。

        http://msdn.microsoft.com/en-us/library/k494fzbf.aspx

        【讨论】:

        • 不是我需要的。我想覆盖标准的 DateTime,以便我们可以指定任何时间 zome.... 例如 DateTimeOffset。为字符串指定 DataType 适用于 positiveInteger、nonPositiveInteger 等...但不适用于 datetime 谢谢
        猜你喜欢
        • 1970-01-01
        • 2011-09-13
        • 1970-01-01
        • 2014-09-05
        • 1970-01-01
        • 2020-05-25
        • 1970-01-01
        • 1970-01-01
        • 2012-05-18
        相关资源
        最近更新 更多