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


74

我有一些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;
    }
}

将XML反序列化为对象时,XmlSerializer一切似乎都很好。我面临的问题是该服务希望日期格式化为YYYY-MM-DD hh:mm:ssXSD生成的代码似乎只能生成YYYY-MM-DD

如果我手动修改XSD以xs:dateTime键入,则生成的C#代码将产生:2010-08-20T20:07:03.915039Z

基本上,我如何强制序列化产生YYYY-MM-DD hh:mm:ss?是否可以对XSD进行某些操作,或者可以对生成的C#代码进行更改?


这是XSD中的错误,该类型xs:date被明确描述为引用date,没有时间部分!
Skolima 2013年

Answers:


145

过去,我已经完成了以下操作来控制日期时间序列化:

  • 忽略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); }
    }
}

4
+1,好的,我曾考虑过类似的解决方案,但它需要我修改工具生成的文件才能添加[XmlIgnore]到令人反感的属性中。尽管这是一个很好的一次性解决方案,但是当源XSD经常使用新功能进行更新时,这听起来并不是一件好事。我想这可能是最好的,从修改XSD类型xs:datexs:string并把它从那里。
wpfwannabe

我同意你的分析。由于SharePoint期望的日期格式,我也遇到了类似的问题。另一种解决方案是坚持使用日期格式使服务更灵活;但是,如您所知,这并不总是替代方案。
kbrimington

2
[XmlElement(DataType =“ date”)]是您真正想要的!:)(请参见下面的答案)。
Tod Thomson

3
虽然[XmlElement(DataType="date")]看起来是“正确的”,但它并没有按照OP请求的方式格式化XML。我yyyy-MM-dd代替了yyyy-MM-dd HH:mm:ss。即使在.NET 4.0中,上述方法也是将自定义格式应用于DateTimeXML对象的普遍接受的方法。
kbrimington

1
这是一个很好的解决方案,但值得指出的是,此设置程序是必需的。我尝试仅使用get来执行此操作(因为这是仅用于输出的情况),但是如果没有setter,SomeDateString的序列化将不会发生。
Michael Murphy

64

使用[XmlElement(DataType = "date")]属性根据DateTime需要设置属性值的格式。

从MSDN

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


6
这看起来是最简单的解决方案。只需将属性添加[XmlElement(DataType="date")]到您的财产
MadBender

12
旧帖子,但是要序列化日期和时间,您属性的正确属性将是:[XmlElement(DataType =“ dateTime”)]
devHead

1
旧帖子,但您也可以[XmlAttribute(DataType="date")]将序列化为Xml属性而不是元素,也可以执行相同的操作
Simply Ged

根据我的测试,当使用属性覆盖时,警告:DataType被完全忽略XmlSerializerXmlAttribute也被忽略。
Suncat2000

4

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

如何从.NET 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>

我还必须指出 清除毫秒之前,我正在这样做:

            var startDateTimeToUse = ssStartDateTime.ToUniversalTime();
            var endDate = DateTime.Now.ToUniversalTime();
            startDateTimeToUse = DateTime.SpecifyKind(startDateTimeToUse, DateTimeKind.Unspecified);
            endDate = DateTime.SpecifyKind(endDate, DateTimeKind.Unspecified);

我不知道这是否对序列化有任何影响


1
+1是我为了避免碰到我们的dal lib而需要的技巧。DateTimeKind.Unspecified将在序列化时删除'Z'符号。
昆顿·史密斯

@JasonCapriotti:我这样做是为了更改值的序列化方式,因此它确实与序列化有关。简单,实际上是修复,我需要什么可能是对对方的不守规矩的PHP unserializer互动
若昂·安图内斯

3

我相信实现IXmlSerializable接口会成功。然后,您可以控制如何序列化和反序列化对象。


1
听起来很有希望,因为它可以轻松插入所有类,并以as的形式生成partial。另一方面,我失去了自动进行公共财产序列化的所有好处,因此我必须重新发明轮子。如果该类只有少数几个属性,这将不是问题。它有很多,而且当XSD遭受更改时,必须维护它似乎是一项艰巨的任务。
wpfwannabe

1

请参阅上面的答案,但要添加-如果只希望在值不为null时输出(例如XML maxOccurs = 0),则可以使用以下方法:

private System.DateTime? someDateField;

public string someDate
{
    get
    {
        return someDateField?.ToString("MM-dd-yyyy");
    }
    set
    {
        dobField = System.DateTime.Parse(value);
    }
}

0

我可能还有其他选择。设置DateTime时,只需减去秒后所有项目的滴答数,例如:

    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定义内的任何内容。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.