Как сериализовать в dateTime

Работаем над получением DateTimes для любого часового пояса. Я использую DateTimeOffset, строку и атрибут XmlElement. Когда я это сделаю, я получаю следующую ошибку:

[InvalidOperationException: dateTime - недопустимое значение для свойства XmlElementAttribute.DataType. dateTime не может быть преобразован в System.String.]
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping (модель TypeModel, String ns, контекст ImportContext, String dataType, XmlAttributes a, Boolean Repeats, Boolean openModel, RecursionLimiter limiter) +450

[InvalidOperationException: произошла ошибка, отражающая тип System.String.]
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping (модель TypeModel, String ns, контекст ImportContext, String dataType, XmlAttributes a, Boolean Repeats, Boolean openModel, Ограничитель RecursionLimiter) +1621
System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping (средство доступа MemberMapping, модель FieldModel, XmlAttributes a, String ns, Type selectionIdentifierType, Boolean rpc, Boolean openModel, RecursionXml50
.Serialization.XmlReflectionImporter.ImportFieldMapping (родительский элемент StructModel, модель FieldModel, XmlAttributes a, String ns, ограничитель RecursionLimiter) +139
System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers, StringMapping тип open, StructMapping модели ограничитель) +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;
    }
}

person david valentine    schedule 21.11.2008    source источник
comment
Только для записи. Остерегайтесь DateTimeOffset. При использовании сериализации WCF возникают некоторые проблемы DateTimeOffset.   -  person Dmitrii Lobanov    schedule 21.02.2012


Ответы (6)


Взгляните на этот вопрос StackOverflow о сериализации дат и UTC:

Лучшие практики сериализации DateTime в .Net framework 3.5 / SQL Server 2008

Нет необходимости создавать специальное свойство только для выполнения сериализации.

person Jason Jackson    schedule 21.11.2008
comment
Комментарий говорит сам за себя ... даже мысль о том, что время ISO позволяет что угодно ... Если вы абсолютно, безусловно, должны знать сам часовой пояс (то есть, указанное выше может быть Восточное стандартное время или Центральное летнее время), вам необходимо создать свой собственный тип данных, который предоставляет эти штуки. Реализовать iXmlSerializer - person david valentine; 21.11.2008
comment
UTC - это старый способ (уверен, что сериализуется), но он не отвечает на вопрос о сериализации DateTimeOffset (с соответствующим часовым поясом). Прочтите статью MSDN по этому вопросу, текущий совет от Microsoft - DateTimeOffset для обработки / хранения и TimeZoneInfo для вычислений в любых часовых поясах: msdn.microsoft.com/en-us/library/bb384267 (v = vs.110) .aspx Только варианты могут использовать другой сериализатор (DataContract или NetDataContract), добавьте свойства, такие как обходной путь, который я добавил в статью о подключении MS, или создайте свою собственную структуру с UTC и идентификатором часового пояса, но это менее стандартно - person Tony Wall; 15.04.2014

Это то, что сработало для меня

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); }
}
person jhilden    schedule 21.02.2012

Используйте методы XmlConvert.ToDateTimeOffset () и .ToString () для правильной сериализации и десериализации DateTimeOffset в свойстве обходного пути XmlSerializer.

Полный образец в статье Microsoft Connect здесь и подтверждение того, что, к сожалению, Microsoft не исправит эту оплошность (она должна была изначально поддерживаться XmlSerializer как любой примитивный тип):

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

person Tony Wall    schedule 10.04.2014

Я бы посоветовал вам сериализовать DateTime как long (это то, что реализация использует внутри для хранения фактического значения).

Вы можете использовать DateTime.Ticks для получения значения, и у него есть конструктор, который занимает много времени (Int64).

person Asher    schedule 21.11.2008
comment
Обратное преобразование кажется вопросом использования конструктора, но это обсуждение полезно: stackoverflow.com/questions/1489243/ - person Stephen Hosking; 01.07.2017

Это 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
person nipunasudha    schedule 13.02.2019

Тип данных свойства creationTimeX - строка, а тип данных XmlSerialization - DateTime. Вот почему вы получаете то исключение.

Вы можете исправить это, изменив тип данных на DateTime.

Также для вашей проблемы текущего времени для любого часового пояса вам нужно будет применить DateTime.Now.ToUniveralTime() и применить к нему соответствующий шаблон DateTimeFormat.

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

person user35559    schedule 21.11.2008
comment
Не то, что мне нужно. Я хотел бы переопределить стандартный DateTime, чтобы мы могли указать ЛЮБОЙ зоме времени .... например DateTimeOffset. Указание DataType для строк работает для PositiveInteger, nonPositiveInteger и т.д., но не работает для datetime, спасибо - person david valentine; 21.11.2008