如何将数据序列化为日期时间格式

5

为任何时区获取DateTimeTimes。 我正在使用DateTimeOffset,字符串和XmlElement属性。 当我这样做时,我会收到以下错误:

[InvalidOperationException:“dateTime”是 XmlElementAttribute.DataType属性的无效值。 dateTime无法转换为System.String。]
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter) +450

[InvalidOperationException:反射类型“System.String”时出错。]
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter) +1621
System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType, Boolean rpc, Boolean openModel, RecursionLimiter limiter) +8750
System.Xml.Serialization.XmlReflectionImporter.ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, String ns, RecursionLimiter limiter) +139
System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter) +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 存在一些问题。 - Dmitrii Lobanov
6个回答

3
这是对我有效的方法。
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

注释已经说明了一切...尽管ISO时间允许任何事情...如果您绝对必须知道时区本身(即上面可能是东部标准时间或中央夏令时),则需要创建自己的数据类型来公开这些部分。实现iXmlSerializer。 - david valentine
UTC是旧的方式(确保序列化),但不能回答有关序列化DateTimeOffset(与相关时区)的问题。请阅读MSDN文章,微软目前的建议是在涉及任何时区的计算中使用DateTimeOffset进行处理/存储和TimeZoneInfo: http://msdn.microsoft.com/en-us/library/bb384267(v=vs.110).aspx 唯一的选择是使用不同的序列化程序(DataContract或NetDataContract),添加属性,如我在MS连接文章中添加的解决方法,或创建自己的结构体,其中包含UTC和时区ID,但这不太标准。 - Tony Wall

1

1
我建议您将DateTime序列化为long类型(这是实现内部用于存储实际值的类型)。
您可以使用DateTime.Ticks获取该值,并且它有一个以long(Int64)为参数的构造函数。

转换回来似乎只需要使用构造函数,但是这个讨论很有帮助:https://dev59.com/B3I_5IYBdhLWcg3wMf9_ - Stephen Hosking

0

现在是2019年,我发现了一个很棒的单脚本用于自定义类型和属性绘制器UDateTime来自于这个gist

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

0
属性 creationTimeX 的数据类型是字符串,而 XmlSerialization 的数据类型是 DateTime。这就是为什么你会收到该异常的原因。
你可以通过将数据类型更改为 DateTime 来修复此问题。
对于任何时区的当前时间问题,你需要应用 DateTime.Now.ToUniveralTime() 并在其上应用适当的 DateTimeFormat 模式。

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


不是我需要的。我想要覆盖标准的DateTime,以便我们可以指定任何时区...例如DateTimeOffset。为字符串指定数据类型适用于positiveInteger、nonPositiveInteger等...但不适用于日期时间。谢谢。 - david valentine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接