5

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;
    }
}
John Saunders
  • 160,644
  • 26
  • 247
  • 397
david valentine
  • 4,625
  • 2
  • 21
  • 15
  • Just for the record. Beware of `DateTimeOffset`. There're some problems serializing `DateTimeOffset` when using WCF serialization. – Dmitrii Lobanov Feb 21 '12 at 16:51

6 Answers6

3

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); }
}
Dmitrii Lobanov
  • 4,897
  • 1
  • 33
  • 50
jhilden
  • 12,207
  • 5
  • 53
  • 76
2

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.

Community
  • 1
  • 1
Jason Jackson
  • 17,016
  • 8
  • 49
  • 74
  • The comment says it all.. even thought ISO time allows anything... If you absolutely, positively must know the timezone itself (i.e. the above could be Eastern Standard Time or Central Daylight Time), you need to create your own datatype which exposes those pieces. Implement iXmlSerializer – david valentine Nov 21 '08 at 17:21
  • UTC is the old way (sure that serializes) but doesn't answer the question about serializing DateTimeOffset (with time zone relevant). Read the MSDN article on the subject, current advice from Microsoft is DateTimeOffset for processing/storage and TimeZoneInfo for calculations anywhere time zones are involved: http://msdn.microsoft.com/en-us/library/bb384267(v=vs.110).aspx Only options are to use a different serializer (DataContract or NetDataContract), add properties like the workaround I added to the MS connect article, or make your own struct with UTC and timezone ID but that's less standard – Tony Wall Apr 15 '14 at 12:10
1

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

Tony Wall
  • 1,382
  • 20
  • 18
1

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

Dovydas Šopa
  • 2,282
  • 8
  • 26
  • 34
Asher
  • 1,867
  • 15
  • 24
  • Converting back seems to be just a matter of using the constructor, but this discussion is helpful: https://stackoverflow.com/questions/1489243/how-can-i-convert-ticks-to-a-date-format – Stephen Hosking Jul 01 '17 at 09:09
0

The datatype of the property creationTimeX is string while the XmlSerialization datatype is DateTime. That's 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.

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

p.campbell
  • 98,673
  • 67
  • 256
  • 322
user35559
  • 1,018
  • 3
  • 11
  • 21
  • Not what I need. I would like to override the standard DateTime, so that we can specify ANY time zome.... eg DateTimeOffset. Specifing DataType for strings works for positiveInteger, nonPositiveInteger etc... but does not work for datetime thanks – david valentine Nov 21 '08 at 15:56
0

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
nipunasudha
  • 2,427
  • 2
  • 21
  • 46