不要从序列化的DateTime对象序列化或删除TimeZone

我给出的奇怪任务是使用XML Serialization序列化LARGE对象。 此对象包含多个嵌套的UserDefined类,具有多个DateTime字段。 DateTime数据的要求是它必须始终显示在最初创建和设置数据的用户的TimeZone中。 因此,我无法使用UTC或本地时间,因为在反序列化时,它们将不会与它们相同。 我也无法以UTC显示值,它们必须以本地时间显示。 我需要的是一些奇怪的序列化格式,代表“绝对本地时间”的概念……即“没有TimeZone的本地时间”。

我可以使用正则表达式从日期字符串中删除TZ,这很容易。 但是我正在处理的对象的庞大大小意味着我经常会得到一个OutOfMemoryException。 我看着它在没有调试的情况下运行一次,并且在操作过程中我使用的内存从100k增加到800k。 不太好。 那是一个较小的文件。

Doc.DocumentElement.InnerXML = Regex.Replace(Doc.DocumentElement.InnerXML, "(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2})(\\+|-)(\\d{2}:\\d{2})", "$1") 

到目前为止,我看到的唯一选项是创建所有dateTime字段的副本,将DT字段本身设置为“XmlIgnore()”,然后在重新加载文档后手动恢复序列化字符串数据中的所有日期。 这也不实用。 请参见自定义DateTime XML序列化

有没有办法强制序列化引擎在没有TimeZone数据的情况下序列化DateTime对象? 优选地,通用的东西不必单独应用于对象中的每个DT属性?

!!编辑!!

我可能找到了部分解决方案。 它至少可以帮助前进。 DateTimeKind.Unspecified,在序列化时,似乎没有附加任何TimeZone数据。 这是我正在寻找的解决方案。 使用DateTime.SpecifyKind强制转换我的所有DateTime数据?

 public DateTime? StartDate { get { return _StartDate; } set { if (_StartDate == value) return; if (value != null) _StartDate = DateTime.SpecifyKind(value.Value, DateTimeKind.Unspecified); else _StartDate = value; OnPropertyChanged("StartDate"); } } 

我认为您需要重新评估您的要求或假设。

你写了:

DateTime数据的要求是它必须始终显示在最初创建和设置数据的用户的TimeZone中。 因此,我不能使用UTC或本地时间,因为当反序列化时,它们将不会与它们相同。

我不认为你的分析是正确的。 在我看来,您不必要将序列化与存储混合在一起,并向用户显示“显示”。 但这两件事情不应该有关系。 我理解的要求是:

  • 您希望序列化和反序列化许多不同的时间值。
  • 当“显示”那些时间时,您希望显示器使用原始时区。

这些是不同的要求。

序列化DateTime会存储一个时刻,但是会丢失TimeZone信息。 在我看来,您需要为每个XML文档单独序列化时区信息。 如果你这样做,那么反序列化的时间会自动生效 – 你总能得到你最初存储的存储的确切时间。

显示时间时,请使用单独存储在XML文档中的时区信息。 如果原始对象中不存在包含TimeZone的属性,那么在我看来,您的对象模型不太适合应用程序的要求,在这种情况下,您需要修改对象定义以包含标识时区。 (参见http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx )

至于内存不足错误,这可能是一个无关的问题。 它也可能是由于您使用大型XmlDocument对象。 使用Xml序列化时,这应该是不必要的。

我建议创建自定义类型来保存这样的日期。 它可以让你以任何你想要的方式处理序列化。 更简单的方法是考虑将它们保存为ISO8601格式的字符串(2012-05-04-26T12:57),而没有为此情况精确指定的时区。

从序列化数据中删除时区可能不是一个好主意,因为一旦您真正需要节省绝对时间,它就会引起有趣的问题。 特别是如果代码是共享的。

找到答案。 这不是我想要的,但作为一种有效的工作。

 private static readonly Regex DTCheck = new Regex(@"(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})([\+|-]\d{2}:\d{2})"); ///  /// Removes any instances of the TimeZoneOffset from the RigX after it has been serialized into an XMLString ++ Called from the "Save" process ///  ///  /// StringReader referencing the re-formatted XML String private static StringReader RemoveTZOffsetFromRigX(RigX rigx) { StringBuilder sb = new StringBuilder(); StringWriter sw = new StringWriter(sb); XmlSerializer ser = new XmlSerializer(typeof(RigX)); ser.Serialize(sw, rigx); string xmlText = sb.ToString(); if (DTCheck.IsMatch(xmlText)) xmlText = DTCheck.Replace(xmlText, "$1"); StringReader Sreader = new StringReader(xmlText); return Sreader; } ///  /// Removes the TimeZone offset from a RigX as referenced by stream. Returns a reader linked to the new stream ++ Called from the "Load" process ///  /// stream containing the initial RigX XML String /// StringReader referencing the re-formatted XML String private StringReader RemoveTZOffsetFromXML(MemoryStream stream) { stream.Position = 0; StreamReader reader = new StreamReader(stream, Encoding.UTF8); string xmlText = reader.ReadToEnd(); reader.Close(); stream.Close(); if (DTCheck.IsMatch(xmlText)) xmlText = DTCheck.Replace(xmlText, "$1"); StringReader Sreader = new StringReader(xmlText); return Sreader; } 

在从文件中读取XML之后,在通过序列化程序运行它之前,在裸XML文本上运行Regex以删除偏移量。 该函数返回一个针对修改后的XML字符串运行的字符串阅读器,然后可以通过反序列化将其运行到对象中。

您可以使用stringBuilder拦截序列化的xml,而不是使用序列化程序将xml直接保存到输出流。 然后使用与加载过程中相同的过程,通过RegularExpression移除TimeZone偏移量,然后返回链接到已修改文本的StringReader,然后将其用于将数据写回文件。

略有hackish的感觉,但有效。 但是内存非常密集,如果可以,请尽量避免直接调试函数,或者如果必须,请尽量不要评估字符串,上次我尝试完全崩溃了我的VS实例。