Cómo serializar un intervalo de tiempo en XML
Estoy intentando serializar un objeto.NET TimeSpan
en XML y no funciona. Un rápido Google ha sugerido que mientras TimeSpan
es serializable, el XmlCustomFormatter
no proporciona métodos para convertir TimeSpan
objetos hacia y desde XML.
Un enfoque sugerido fue ignorar el TimeSpan
para la serialización, y en su lugar serializar el resultado de TimeSpan.Ticks
(y usar new TimeSpan(ticks)
para la deserialización). Un ejemplo de esto es el siguiente:
[Serializable]
public class MyClass
{
// Local Variable
private TimeSpan m_TimeSinceLastEvent;
// Public Property - XmlIgnore as it doesn't serialize anyway
[XmlIgnore]
public TimeSpan TimeSinceLastEvent
{
get { return m_TimeSinceLastEvent; }
set { m_TimeSinceLastEvent = value; }
}
// Pretend property for serialization
[XmlElement("TimeSinceLastEvent")]
public long TimeSinceLastEventTicks
{
get { return m_TimeSinceLastEvent.Ticks; }
set { m_TimeSinceLastEvent = new TimeSpan(value); }
}
}
Si bien esto parece funcionar en mi breve prueba, ¿es esta la mejor manera de lograr esto?
¿Hay una mejor manera de serializar un intervalo de tiempo hacia y desde XML?
13 answers
La forma en que ya has publicado es probablemente la más limpia. Si no te gusta la propiedad extra, podrías implementar IXmlSerializable
, pero entonces tienes que hacer todo, lo que en gran medida frustra el punto. Me encantaría usar el enfoque que has publicado; es (por ejemplo) eficiente (sin análisis complejo, etc.), independiente de la cultura, sin ambigüedades, y los números de tipo de marca de tiempo son fáciles y comúnmente entendidos.
Como un aparte, a menudo añado:
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
Esto solo lo oculta en la interfaz de usuario y en haciendo referencia a DLL, para evitar confusiones.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-12 10:08:54
Esto es solo una ligera modificación en el enfoque sugerido en la pregunta, pero este problema de Microsoft Connect recomienda usar una propiedad para serialización como esta:
[XmlIgnore]
public TimeSpan TimeSinceLastEvent
{
get { return m_TimeSinceLastEvent; }
set { m_TimeSinceLastEvent = value; }
}
// XmlSerializer does not support TimeSpan, so use this property for
// serialization instead.
[Browsable(false)]
[XmlElement(DataType="duration", ElementName="TimeSinceLastEvent")]
public string TimeSinceLastEventString
{
get
{
return XmlConvert.ToString(TimeSinceLastEvent);
}
set
{
TimeSinceLastEvent = string.IsNullOrEmpty(value) ?
TimeSpan.Zero : XmlConvert.ToTimeSpan(value);
}
}
Esto serializar un intervalo de tiempo de 0:02:45 como:
<TimeSinceLastEvent>PT2M45S</TimeSinceLastEvent>
Alternativamente, el DataContractSerializer
soporta TimeSpan.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-21 15:58:02
Algo que puede funcionar en algunos casos es darle a su propiedad pública un campo de respaldo, que es un intervalo de tiempo, pero la propiedad pública se expone como una cadena.
Eg:
protected TimeSpan myTimeout;
public string MyTimeout
{
get { return myTimeout.ToString(); }
set { myTimeout = TimeSpan.Parse(value); }
}
Esto está bien si el valor de la propiedad se usa principalmente en la clase contenedora o clases herederas y se carga desde la configuración xml.
Las otras soluciones propuestas son mejores si desea que la propiedad pública sea un valor de intervalo de tiempo utilizable para otras clases.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-06 19:01:17
Combinando una respuesta de serialización de color y esta solución original (que es genial por sí misma) obtuve esta solución:
[XmlElement(Type = typeof(XmlTimeSpan))]
public TimeSpan TimeSinceLastEvent { get; set; }
Donde XmlTimeSpan
la clase es así:
public class XmlTimeSpan
{
private const long TICKS_PER_MS = TimeSpan.TicksPerMillisecond;
private TimeSpan m_value = TimeSpan.Zero;
public XmlTimeSpan() { }
public XmlTimeSpan(TimeSpan source) { m_value = source; }
public static implicit operator TimeSpan?(XmlTimeSpan o)
{
return o == null ? default(TimeSpan?) : o.m_value;
}
public static implicit operator XmlTimeSpan(TimeSpan? o)
{
return o == null ? null : new XmlTimeSpan(o.Value);
}
public static implicit operator TimeSpan(XmlTimeSpan o)
{
return o == null ? default(TimeSpan) : o.m_value;
}
public static implicit operator XmlTimeSpan(TimeSpan o)
{
return o == default(TimeSpan) ? null : new XmlTimeSpan(o);
}
[XmlText]
public long Default
{
get { return m_value.Ticks / TICKS_PER_MS; }
set { m_value = new TimeSpan(value * TICKS_PER_MS); }
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:40
Puede crear una envoltura de luz alrededor de la estructura TimeSpan:
namespace My.XmlSerialization
{
public struct TimeSpan : IXmlSerializable
{
private System.TimeSpan _value;
public static implicit operator TimeSpan(System.TimeSpan value)
{
return new TimeSpan { _value = value };
}
public static implicit operator System.TimeSpan(TimeSpan value)
{
return value._value;
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
_value = System.TimeSpan.Parse(reader.ReadContentAsString());
}
public void WriteXml(XmlWriter writer)
{
writer.WriteValue(_value.ToString());
}
}
}
Resultado serializado de la muestra:
<Entry>
<StartTime>2010-12-06T08:45:12.5</StartTime>
<Duration>2.08:29:35.2500000</Duration>
</Entry>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-08 21:05:38
Una opción más legible sería serializar como una cadena y usar el método TimeSpan.Parse
para deserializarla. Podrías hacer lo mismo que en tu ejemplo pero usando TimeSpan.ToString()
en el getter y TimeSpan.Parse(value)
en el setter.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-28 15:19:30
Otra opción sería serializarlo usando la clase SoapFormatter
en lugar de la clase XmlSerializer
.
El archivo XML resultante se ve un poco diferente...algunas etiquetas con prefijo "SOAP", etc...pero puede hacerlo.
Esto es lo que SoapFormatter
serializó un intervalo de tiempo de 20 horas y 28 minutos serializado a:
<myTimeSpan>P0Y0M0DT20H28M0S</myTimeSpan>
Para usar la clase SoapFormatter, necesita agregar referencia a System.Runtime.Serialization.Formatters.Soap
y usar el espacio de nombres del mismo nombre.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-28 15:20:12
Mi versión de la solución :)
[DataMember, XmlIgnore]
public TimeSpan MyTimeoutValue { get; set; }
[DataMember]
public string MyTimeout
{
get { return MyTimeoutValue.ToString(); }
set { MyTimeoutValue = TimeSpan.Parse(value); }
}
Editar: asumiendo que es nullable...
[DataMember, XmlIgnore]
public TimeSpan? MyTimeoutValue { get; set; }
[DataMember]
public string MyTimeout
{
get
{
if (MyTimeoutValue != null)
return MyTimeoutValue.ToString();
return null;
}
set
{
TimeSpan outValue;
if (TimeSpan.TryParse(value, out outValue))
MyTimeoutValue = outValue;
else
MyTimeoutValue = null;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-14 10:54:46
Timespan almacenado en xml como número de segundos, pero es fácil de adoptar, espero. Timespan serializado manualmente (implementando IXmlSerializable):
public class Settings : IXmlSerializable
{
[XmlElement("IntervalInSeconds")]
public TimeSpan Interval;
public XmlSchema GetSchema()
{
return null;
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("IntervalInSeconds", ((int)Interval.TotalSeconds).ToString());
}
public void ReadXml(XmlReader reader)
{
string element = null;
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
element = reader.Name;
else if (reader.NodeType == XmlNodeType.Text)
{
if (element == "IntervalInSeconds")
Interval = TimeSpan.FromSeconds(double.Parse(reader.Value.Replace(',', '.'), CultureInfo.InvariantCulture));
}
}
}
}
Hay un ejemplo más completo: https://bitbucket.org/njkazakov/timespan-serialization
Mira la configuración.cs. Y hay un código complicado para usar XmlElementAttribute.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-26 08:14:31
Para la serialización de contratos de datos utilizo lo siguiente.
- Mantener la propiedad serializada privada mantiene limpia la interfaz pública.
- El uso del nombre de propiedad pública para la serialización mantiene el XML limpio.
Public Property Duration As TimeSpan
<DataMember(Name:="Duration")>
Private Property DurationString As String
Get
Return Duration.ToString
End Get
Set(value As String)
Duration = TimeSpan.Parse(value)
End Set
End Property
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-03 01:10:43
No se puede comentar ni clasificar, pero el comentario SoapDuration
[XmlElement, Type=SoapDuration]
public TimeSpan TimeSinceLastEvent
O
public SoapDuration TimeSinceLastEventTicks
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-31 09:02:05
Si no desea ninguna solución alternativa, utilice la clase DataContractSerializer de System.Ejecución.Serialización.DLL.
using (var fs = new FileStream("file.xml", FileMode.Create))
{
var serializer = new DataContractSerializer(typeof(List<SomeType>));
serializer.WriteObject(fs, _items);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-21 18:13:49
Prueba esto:
//Don't Serialize Time Span object.
[XmlIgnore]
public TimeSpan m_timeSpan;
//Instead serialize (long)Ticks and instantiate Timespan at time of deserialization.
public long m_TimeSpanTicks
{
get { return m_timeSpan.Ticks; }
set { m_timeSpan = new TimeSpan(value); }
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-09 04:17:45