C# 强制XmlSerializer将DateTime序列化为';YYYY-MM-DD hh:MM:ss';

C# 强制XmlSerializer将DateTime序列化为';YYYY-MM-DD hh:MM:ss';,c#,.net,xml-serialization,C#,.net,Xml Serialization,我有一个用于RESTful服务的XSD模式。当与xsd.exe工具结合使用以生成C#代码时,xsd的xs:date生成以下代码: [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, DataType="date")] public System.DateTime time { get { return this.timeField;

我有一个用于RESTful服务的XSD模式。当与
xsd.exe
工具结合使用以生成C#代码时,xsd的
xs:date
生成以下代码:

[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, DataType="date")]
public System.DateTime time {
    get {
        return this.timeField;
    }
    set {
        this.timeField = value;
    }
}
当使用
XmlSerializer
将XML反序列化为对象时,一切似乎都很好。我面临的问题是,该服务希望将日期格式化为
YYYY-MM-DD hh:MM:ss
,而XSD生成的代码似乎只生成
YYYY-MM-DD

如果我手动将XSD修改为
xs:dateTime
类型,生成的C#代码将生成:
2010-08-20T20:07:03.915039Z


基本上,如何强制序列化生成
YYYY-MM-DD hh:MM:ss
?是否需要对XSD做些什么,或者我可以做些什么来更改生成的C代码?

在过去,我已经做了以下工作来控制日期时间序列化:

  • 忽略DateTime属性
  • 创建一个伪字符串属性,以我想要的方式序列化/反序列化
以下是一个例子:

public class SomeClass
{
    [XmlIgnore]
    public DateTime SomeDate { get; set; }

    [XmlElement("SomeDate")]
    public string SomeDateString
    {
        get { return this.SomeDate.ToString("yyyy-MM-dd HH:mm:ss"); }
        set { this.SomeDate = DateTime.Parse(value); }
    }
}

我相信实现
IXmlSerializable
接口将起到一定的作用。然后,您可以控制序列化和反序列化对象的方式。

使用
[xmlement(DataType=“date”)]
属性根据需要格式化
DateTime
属性值

:

注:
注释publicationdate字段的属性具有 数据类型属性。.NET Framework中没有匹配的类型 类型xs:date完全相同。最接近的匹配项是System.DateTime, 它存储日期和时间数据。将数据类型属性指定为 “date”确保XmlSerializer只序列化日期 DateTime对象的一部分


如果你只需要清除毫秒部分。参考:

基本上,你可以这样做:

  startDateTimeToUse = startDateTimeToUse.AddTicks(-(startDateTimeToUse.Ticks % TimeSpan.TicksPerSecond));
  endDate = endDate.AddTicks(-(endDate.Ticks % TimeSpan.TicksPerSecond));
我可以确认,这将序列化为:

            <startDate>2015-10-31T12:13:04</startDate>
            <endDate>2016-11-10T12:13:06</endDate>

我不知道在这一点上它是否对序列化有任何影响

请参见上面的答案,但要添加--如果您只希望在值为非null(例如XML maxOccurs=0)时输出,您可以使用如下内容:

private System.DateTime? someDateField;

public string someDate
{
    get
    {
        return someDateField?.ToString("MM-dd-yyyy");
    }
    set
    {
        dobField = System.DateTime.Parse(value);
    }
}
我可能有另一个选择。 设置日期时间时,只需减去秒后的所有刻度数,如:

    public DateTime Dt
        {
        get => _dt;
        set
            {
            _dt = value;
            long elapsedTicks = _dt.Ticks - new DateTime(_dt.Year, _dt.Month, _dt.Day, _dt.Hour, _dt.Minute, _dt.Second).Ticks;
            TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);
            _dt = _dt.Subtract(elapsedSpan);
            }
        }
private DateTime _dt = default(DateTime);

这样,当你序列化你的DateTime(Dt)时,毫秒将不会被使用,你将得到一个值hh:mm:ss,这至少是它给我的。这样就不需要修改XML定义中的任何内容。

+1,好的,我已经考虑过类似的解决方案,但需要修改工具生成的文件,将
[XmlIgnore]
添加到有问题的属性中。尽管这是一个很好的一次性解决方案,但当源XSD经常使用新特性更新时,这听起来并不是一件好事。我认为最好将XSD类型从
xs:date
修改为
xs:string
,然后从那里开始。我同意你的分析。由于SharePoint预期的日期格式,我遇到了类似的问题。另一种解决方案是坚持服务在日期格式上更加灵活;但是,正如您所清楚的,这并不总是一个替代方案。[xmlement(DataType=“date”)]才是您真正想要的(请参见下面的答案)。虽然
[xmlement(DataType=“date”)]
似乎是“正确的”,但它并没有按照OP请求的方式格式化XML。我得到了
yyyy-MM-dd
而不是
yyy-MM-dd HH:MM:ss
。即使在.NET 4.0中,上述方法也是将自定义格式应用于XML中的
DateTime
对象的公认方法。这是一个很好的解决方案,但值得指出的是,setter是必需的。我尝试只使用get(因为这是一种仅用于输出的情况)来实现这一点,但是如果没有setter,SomeDateString的序列化将不会发生。听起来很有希望,因为可以轻松地将它插入,所有类都生成为
部分
。另一方面,我失去了所有自动公共属性序列化的好东西,所以我必须重新发明轮子。如果类只有几个属性,那么这就不会是问题。它有很多这样的功能,在XSD发生变化时必须维护这些功能听起来是一项艰巨的任务。这看起来是最简单的解决方案。只需将属性
[xmlement(DataType=“date”)]
添加到您的propertyOld post,但要序列化日期和时间,您的属性的正确属性应该是:[xmlement(DataType=“dateTime”)]Old post,但您也可以对
[XmlAttribute(DataType=“date”)]执行相同的操作
要序列化为Xml属性而不是元素,请注意:
XmlSerializer
在使用属性重写时,根据我的测试,会完全忽略
DataType
xmldattribute
也被忽略。这是XSD中的一个错误,类型
xs:date
被明确描述为引用日期,没有时间部分!看看+1是我为了避免触碰我们的dal库而需要的黑客攻击。DateTimeKind.Unspecified将在序列化时删除“Z”符号。@JasonCapriotti:我这样做是为了更改值序列化的方式,因此它确实与序列化有关。更简单,实际上是我需要的修复,与另一端可能是一个难以控制的PHP非序列化程序进行交互
    public DateTime Dt
        {
        get => _dt;
        set
            {
            _dt = value;
            long elapsedTicks = _dt.Ticks - new DateTime(_dt.Year, _dt.Month, _dt.Day, _dt.Hour, _dt.Minute, _dt.Second).Ticks;
            TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);
            _dt = _dt.Subtract(elapsedSpan);
            }
        }
private DateTime _dt = default(DateTime);