【问题标题】:`XmlConvert.ToDateTime(String)` and `XmlConvert.ToString(DateTime)` outputs are inconsistent`XmlConvert.ToDateTime(String)` 和 `XmlConvert.ToString(DateTime)` 输出不一致
【发布时间】:2011-12-08 21:58:24
【问题描述】:

我遇到了XmlConvertDateTime 的问题。

当使用XmlConvert.ToDateTime(String) 转换某些字符串时,然后将结果DateTime 转换回使用XmlConvert.ToString(DateTime) 的字符串,结果字符串与原始字符串不同,并且取决于本地时区。

以下控制台应用程序代码演示了该问题:

using System;
using System.Xml;

namespace DateTimeXmlConvertTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Original Value\t\t\t\tNew Value");
            Console.WriteLine("--------------\t\t\t\t---------");

            for (int i = -12; i <= 12; i++)
            {
                string sign = i < 0 ? "" : "+";

                string originalString = "2011-10-01T01:18:54.6652000" + sign + i.ToString("D2") + ":00";
                DateTime now = XmlConvert.ToDateTime(originalString);
                string newValue = XmlConvert.ToString(now);
                Console.WriteLine(originalString + "\t" + newValue);
            }
        }
    }
}

在我的 PC 上运行此程序时(Windows 7 x64,TimeZone UTC+02:00 with Daylight)我有以下输出:

Original Value                          New Value
--------------                          ---------
2011-10-01T01:18:54.6652000-12:00       2011-10-01T16:18:54.6652000+03:00
2011-10-01T01:18:54.6652000-11:00       2011-10-01T15:18:54.6652000+03:00
2011-10-01T01:18:54.6652000-10:00       2011-10-01T14:18:54.6652000+03:00
2011-10-01T01:18:54.6652000-09:00       2011-10-01T13:18:54.6652000+03:00
2011-10-01T01:18:54.6652000-08:00       2011-10-01T12:18:54.6652000+03:00
2011-10-01T01:18:54.6652000-07:00       2011-10-01T11:18:54.6652000+03:00
2011-10-01T01:18:54.6652000-06:00       2011-10-01T10:18:54.6652000+03:00
2011-10-01T01:18:54.6652000-05:00       2011-10-01T09:18:54.6652000+03:00
2011-10-01T01:18:54.6652000-04:00       2011-10-01T08:18:54.6652000+03:00
2011-10-01T01:18:54.6652000-03:00       2011-10-01T07:18:54.6652000+03:00
2011-10-01T01:18:54.6652000-02:00       2011-10-01T06:18:54.6652000+03:00
2011-10-01T01:18:54.6652000-01:00       2011-10-01T05:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+00:00       2011-10-01T04:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+01:00       2011-10-01T03:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+02:00       2011-10-01T02:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+03:00       2011-10-01T01:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+04:00       2011-10-01T00:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+05:00       2011-09-30T23:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+06:00       2011-09-30T22:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+07:00       2011-09-30T21:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+08:00       2011-09-30T20:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+09:00       2011-09-30T19:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+10:00       2011-09-30T18:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+11:00       2011-09-30T17:18:54.6652000+03:00
2011-10-01T01:18:54.6652000+12:00       2011-09-30T16:18:54.6652000+03:00

当转换成不同的字符串,然后从它得到不同的字符串时,怎么可能?

有没有办法让它在这种情况下输出原始字符串?

谢谢。

【问题讨论】:

  • 您期望什么?您在不同的时区有不同的 DateTime 实例。使用这些方法的目标是拥有一个单一的时区,因此它们是一致的。如果您希望能够找回时间,则需要跟踪时区。
  • 我希望 ToString() 创建与从(ToDateTime())创建的 DateTime 实例完全相同的字符串。使用这些方法的目的是与 xml dateTime 格式相互转换,而不是修改/计算时区,只需使用与 DateTime 实例中完全相同的时区。
  • 请看我的回答。您正在使用过时的方法,无法控制时区的解释方式。

标签: c# .net xml timezone


【解决方案1】:

首先,XmlConvert.ToDateTime(String) 重载已过时。该文档明确指定您应该改用XmlConvert.ToDateTime(String, XmlDateTimeSerializationMode)。使用它,您可以指定XmlDateTimeSerializationMode,记录如下:

XmlDateTimeSerializationMode 值之一,用于指定日期是否应转换为本地时间或保留为协调世界时 (UTC)(如果它是 UTC 日期)。

当您拥有DateTime 的实例时,它的构造方式(例如它的时区)将会丢失。时区将从原始字符串正确解析并转换为 UTC 或本地时间,但在此过程中会丢失转换的内容。

如果您想保留时区偏移量,请使用 DateTimeOffset 类。它的行为类似于DateTime,但保留了创建它的时区偏移量。 XmlConvert 有一个 ToDateTimeOffset 方法可以完全满足您的需求。这是一个工作示例:

Console.WriteLine("{0,33}\t{1,33}", "Original Value", "New Value");
Console.WriteLine("{0}\t{0}", new String('-', 33));

for (int i = -12; i <= 12; i++)
{
    string sign = i < 0 ? "" : "+";
    string originalString = String.Format(
        "2011-10-01T01:18:54.6652123{0}{1:D2}:00", sign, i);
    DateTimeOffset dateTime = XmlConvert.ToDateTimeOffset(originalString);
    string newString = XmlConvert.ToString(dateTime);
    Console.WriteLine("{0}\t{1}", originalString, newString);
}

您现在唯一的问题是+00:00 将被序列化为Z,如果您自己格式化newString 可以避免这种情况,如下所示:

string newString = String.Format("{0:yyyy-MM-ddTHH:mm:ss.fffffffzzz}", dateTime);

【讨论】:

  • 我尝试了所有其他重载,没有解决不同输出字符串问题的重载。
  • @DxCK,我添加了一个使用 DateTimeOffset 类的工作示例,该类保留了原始时区偏移量。请检查一下。
【解决方案2】:

XmlConvert.ToDateTime(String, XmlDateTimeSerializationMode) 呢, 并保留时区偏移使用参数:

System.Xml.XmlDateTimeSerializationMode.RoundtripKind

【讨论】:

  • 我尝试了所有其他重载,并没有解决不同输出字符串问题的重载。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-07
  • 2018-04-30
  • 2013-04-15
  • 1970-01-01
  • 1970-01-01
  • 2018-12-26
相关资源
最近更新 更多