You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从JavaScriptSerializer迁移到System.Text.Json的日期格式兼容问题

解决System.Text.Json无法识别JavaScriptSerializer日期格式的问题

问题重现

给定如下测试代码,System.Text.Json在解析\/Date(1471463788903)\/格式的日期时会抛出异常,而JavaScriptSerializer和Newtonsoft.Json可以正常解析:

var str = "{ \"Date\": \"\\/Date(1471463788903)\\/\" }";
var js = new JavaScriptSerializer().Deserialize<D>(str);
var newtonsoft = JsonConvert.DeserializeObject<D>(str);
var system = JsonSerializer.Deserialize<D>(str); // 此处抛出异常

public class D { public DateTime Date { get; set; } }

解决办法

System.Text.Json默认不支持JavaScriptSerializer的旧日期格式,需要自定义JsonConverter来处理这种格式:

自定义日期转换器

public class JavaScriptDateTimeConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.String)
            throw new JsonException("日期字段必须为字符串格式");

        var dateStr = reader.GetString();
        // 跳过前后的\/Date(和)\/,提取时间戳部分
        var start = dateStr.IndexOf('(') + 1;
        var end = dateStr.IndexOf(')');
        if (start <= 0 || end <= start)
            throw new JsonException($"无效的日期格式:{dateStr}");

        if (!long.TryParse(dateStr.Substring(start, end - start), out var timestampMs))
            throw new JsonException($"无法解析时间戳:{dateStr}");

        // 转换为DateTime:Unix时间戳(毫秒)转本地时间,和JavaScriptSerializer行为一致
        return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)
            .AddMilliseconds(timestampMs)
            .ToLocalTime();
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        // 如果需要序列化回旧格式,取消下面的注释;否则使用默认ISO格式
        /*
        var utcValue = value.ToUniversalTime();
        var timestampMs = (long)(utcValue - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
        writer.WriteStringValue($"\\/Date({timestampMs})\\/");
        */
        // 默认输出ISO 8601格式
        writer.WriteStringValue(value);
    }
}

使用转换器解析

在反序列化时,将自定义转换器添加到JsonSerializerOptions中:

var options = new JsonSerializerOptions();
options.Converters.Add(new JavaScriptDateTimeConverter());
var system = JsonSerializer.Deserialize<D>(str, options); // 正常解析

潜在问题

  • 时区一致性:JavaScriptSerializer默认将Unix时间戳转换为本地时间,而System.Text.Json默认处理UTC时间。自定义转换器中已对齐JavaScriptSerializer的行为,但如果你的业务依赖UTC时间,需要修改ToLocalTime()为ToUniversalTime()或直接保留UTC时间。
  • 负时间戳支持:如果存在1970年1月1日之前的日期,时间戳会是负数,当前转换器已经支持(因为用了long.TryParse),但如果之前用正则需要确保包含负号。
  • 可空日期的处理:如果模型中存在DateTime?类型,需要单独实现JsonConverter<DateTime?>,或者修改现有转换器兼容可空类型(判断typeToConvert是否为可空类型)。
  • 性能优化:如果需要处理大量日期解析,字符串截取比正则表达式效率更高,当前转换器已使用字符串截取,避免了正则的性能开销。
  • 序列化兼容性:如果需要将对象序列化回旧格式,必须实现Write方法;否则默认会输出ISO 8601格式,可能导致旧系统无法识别。

内容的提问来源于stack exchange,提问作者Yola

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 14:37:48