问题
Working to get DateTimes for any time zone. I'm using DateTimeOffset, and a string, and an XmlElement attribute. When I do, I get the following error:
[InvalidOperationException: 'dateTime' is an invalid value for the XmlElementAttribute.DataType property. dateTime cannot be converted to 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: There was an error reflecting type '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: There was an error reflecting property 'creationTimeX'.] ...
Code:
[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;
}
}
回答1:
Take a look at this StackOverflow question about serializing dates and UTC:
Best practices for DateTime serialization in .Net framework 3.5/SQL Server 2008
No need to create a special property just to accomplish the serialization.
回答2:
This is what worked for me
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); }
}
回答3:
Use the XmlConvert.ToDateTimeOffset() and .ToString() methods to correctly serialize and de-serialize a DateTimeOffset in an XmlSerializer workaround property.
Full sample in the Microsoft Connect article here, and confirmation that unfortunately Microsoft won't fix this oversight (it should have been supported natively by XmlSerializer as any primitive type):
https://connect.microsoft.com/VisualStudio/feedback/details/288349/datetimeoffset-is-not-serialized-by-a-xmlserializer
回答4:
I would suggest you serialize DateTime as a long (which is what the implementation uses internally to store the actual value).
You can use DateTime.Ticks
to get the value and it has a constructor that takes a long (Int64
).
回答5:
David
The datatype of the property(creationTimeX) is string while the XmlSerialization datatype is "dateTime". Thats why you are getting that exception.
You can fix this by Changing the datatype to DateTime
Also for your issue of the current time for any timezone, you would have to apply a DateTime.Now.ToUniveralTime and apply appropriate DateTimeFormat pattern on it.
The steps for these are here
http://msdn.microsoft.com/en-us/library/k494fzbf.aspx
Thanks -RVZ
回答6:
This is 2019, and I found a great single script for a custom type & property drawer UDateTime
from this 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
来源:https://stackoverflow.com/questions/307433/how-to-serialize-to-datetime