Skip to content

Commit 6d877ca

Browse files
committed
✨ feat(Json): 添加 DateTimeNullTo1900Converter 并实现相关测试
- 新增 DateTimeNullTo1900Converter 类,用于将 DateTime 类型的 null 值转换为 1900-01-01 - 在 JsonHelperTest 中添加多个测试用例,验证 DateTimeNullTo1900Converter 的序列化和反序列化行为 - 确保可空 DateTime 类型在序列化时正确处理 null 值 - 验证 JSON 中的 null 值在反序列化时能够正确还原为 1900-01-01
1 parent 1b5e58a commit 6d877ca

File tree

2 files changed

+204
-0
lines changed

2 files changed

+204
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using Newtonsoft.Json;
2+
3+
namespace Bing.Utils.Json.Converters;
4+
5+
/// <summary>
6+
/// 日期时间转换器
7+
/// </summary>
8+
public class DateTimeNullTo1900Converter : JsonConverter
9+
{
10+
/// <summary>
11+
/// 默认日期
12+
/// </summary>
13+
private static readonly DateTime DefaultDate = new DateTime(1900, 1, 1);
14+
15+
/// <summary>
16+
/// 确定此实例是否可以转换指定的对象类型
17+
/// </summary>
18+
/// <param name="objectType">对象类型</param>
19+
public override bool CanConvert(Type objectType) => objectType == typeof(DateTime) || objectType == typeof(DateTime?);
20+
21+
/// <summary>
22+
/// 写入JSON对象
23+
/// </summary>
24+
/// <param name="writer">JSON写入器</param>
25+
/// <param name="value">对象值</param>
26+
/// <param name="serializer">JSON序列化器</param>
27+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
28+
{
29+
var dateTime = value as DateTime?;
30+
if (dateTime == null || dateTime.Value == DefaultDate)
31+
writer.WriteNull();
32+
else
33+
writer.WriteValue(dateTime.Value);
34+
}
35+
36+
/// <summary>
37+
/// 读取JSON对象
38+
/// </summary>
39+
/// <param name="reader">JSON读取器</param>
40+
/// <param name="objectType">对象类型</param>
41+
/// <param name="existingValue">存在值</param>
42+
/// <param name="serializer">JSON序列化器</param>
43+
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
44+
{
45+
var isNullable = (objectType == typeof(DateTime?));
46+
if (reader.TokenType == JsonToken.Null)
47+
return isNullable ? (DateTime?)DefaultDate : DefaultDate;
48+
if (reader.TokenType == JsonToken.String)
49+
{
50+
var str = (string)reader.Value;
51+
if (string.IsNullOrWhiteSpace(str))
52+
return isNullable ? (DateTime?)DefaultDate : DefaultDate;
53+
if (DateTime.TryParse(str, out var result))
54+
return result;
55+
}
56+
if (reader.TokenType == JsonToken.Date && reader.Value is DateTime dt)
57+
return dt;
58+
return isNullable ? (DateTime?)DefaultDate : DefaultDate;
59+
}
60+
}

tests/Bing.Utils.Tests/Json/JsonHelperTest.cs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Bing.Tests.Samples.Json;
22
using Bing.Tests.XUnitHelpers;
33
using Bing.Utils.Json;
4+
using Bing.Utils.Json.Converters;
45
using Newtonsoft.Json;
56

67
namespace Bing.Utils.Tests.Json;
@@ -10,6 +11,8 @@ namespace Bing.Utils.Tests.Json;
1011
/// </summary>
1112
public class JsonHelperTest : TestBase
1213
{
14+
private static readonly DateTime DefaultDate = new(1900, 1, 1);
15+
1316
/// <summary>
1417
/// 初始化一个<see cref="TestBase"/>类型的实例
1518
/// </summary>
@@ -91,4 +94,145 @@ public void Test_ToObject()
9194
var customer = JsonHelper.ToObject<JsonTestSample>("{\"Name\":\"a\"}");
9295
Assert.Equal("a", customer.Name);
9396
}
97+
98+
/// <summary>
99+
/// 测试 - 确保 DateTime 等于 1900-01-01 时,序列化结果为 null
100+
/// </summary>
101+
[Fact]
102+
public void Serialize_1900DateTime_ShouldBeNull()
103+
{
104+
var sample = new JsonDateTimeSample
105+
{
106+
ConfirmTime = DefaultDate,
107+
OptionalTime = DefaultDate
108+
};
109+
110+
var json = JsonConvert.SerializeObject(sample);
111+
Output.WriteLine(json);
112+
Assert.Contains("\"ConfirmTime\":null", json);
113+
Assert.Contains("\"OptionalTime\":null", json);
114+
}
115+
116+
/// <summary>
117+
/// 测试 - 可空时间字段为 null 时,序列化结果应为 null;非 1900 日期应正常序列化
118+
/// </summary>
119+
[Fact]
120+
public void Serialize_NullOptionalTime_ShouldBeNull()
121+
{
122+
var sample = new JsonDateTimeSample
123+
{
124+
ConfirmTime = new DateTime(2025,1,1),
125+
OptionalTime = null
126+
};
127+
128+
var json = JsonConvert.SerializeObject(sample);
129+
Output.WriteLine(json);
130+
Assert.Contains("\"OptionalTime\":null", json);
131+
Assert.Contains("\"ConfirmTime\":\"2025-01-01T00:00:00\"", json);
132+
}
133+
134+
/// <summary>
135+
/// 测试 - JSON 中为 null 的时间字段,反序列化应还原为 1900-01-01
136+
/// </summary>
137+
[Fact]
138+
public void Deserialize_NullJson_ShouldReturnDefaultDate()
139+
{
140+
var json = "{\"ConfirmTime\":null,\"OptionalTime\":null}";
141+
var sample = JsonConvert.DeserializeObject<JsonDateTimeSample>(json);
142+
Output.WriteLine(json);
143+
Assert.Equal(DefaultDate, sample.ConfirmTime);
144+
Assert.Equal(DefaultDate, sample.OptionalTime);
145+
}
146+
147+
/// <summary>
148+
/// 测试 - JSON 中为正常日期字符串时,能够正确反序列化为 DateTime 对象
149+
/// </summary>
150+
[Fact]
151+
public void Deserialize_NormalDate_ShouldParseCorrectly()
152+
{
153+
var json = "{\"ConfirmTime\":\"2023-12-12 10:30:00\",\"OptionalTime\":\"2023-12-12 10:30:00\"}";
154+
155+
var dto = JsonConvert.DeserializeObject<JsonDateTimeSample>(json);
156+
157+
var expected = new DateTime(2023, 12, 12, 10, 30, 0);
158+
Output.WriteLine(json);
159+
Assert.Equal(expected, dto.ConfirmTime);
160+
Assert.Equal(expected, dto.OptionalTime);
161+
}
162+
163+
/// <summary>
164+
/// 测试 - JSON 中为正常日期字符串时,能够正确反序列化为 DateTime 对象
165+
/// </summary>
166+
[Fact]
167+
public void Deserialize_NormalDate_ShouldParseCorrectly_1()
168+
{
169+
var json = "{\"ConfirmTime\":\"2023-12-12T10:30:00\",\"OptionalTime\":\"2023-12-12T10:30:00\"}";
170+
171+
var dto = JsonConvert.DeserializeObject<JsonDateTimeSample>(json);
172+
173+
var expected = new DateTime(2023, 12, 12, 10, 30, 0);
174+
Output.WriteLine(json);
175+
Assert.Equal(expected, dto.ConfirmTime);
176+
Assert.Equal(expected, dto.OptionalTime);
177+
}
178+
179+
/// <summary>
180+
/// 测试 - JSON 中为正常日期字符串时,能够正确反序列化为 DateTime 对象
181+
/// </summary>
182+
[Fact]
183+
public void Deserialize_NormalDate_ShouldParseCorrectly_2()
184+
{
185+
var json = "{\"ConfirmTime\":\"2023-12-12T10:30:00\",\"OptionalTime\":\"1900-01-01T00:00:00\"}";
186+
187+
var dto = JsonConvert.DeserializeObject<JsonDateTimeSample>(json);
188+
189+
var expected = new DateTime(2023, 12, 12, 10, 30, 0);
190+
Output.WriteLine(json);
191+
Assert.Equal(expected, dto.ConfirmTime);
192+
Assert.Equal(DefaultDate, dto.OptionalTime);
193+
}
194+
195+
/// <summary>
196+
/// 测试 - JSON 中为正常日期字符串时,能够正确反序列化为 DateTime 对象
197+
/// </summary>
198+
[Fact]
199+
public void Deserialize_NormalDate_ShouldParseCorrectly_3()
200+
{
201+
var json = "{\"ConfirmTime\":\"2023-12-12T10:30:00\",\"OptionalTime\":null}";
202+
203+
var dto = JsonConvert.DeserializeObject<JsonDateTimeSample>(json);
204+
205+
var expected = new DateTime(2023, 12, 12, 10, 30, 0);
206+
Output.WriteLine(json);
207+
Assert.Equal(expected, dto.ConfirmTime);
208+
Assert.Equal(DefaultDate, dto.OptionalTime);
209+
}
210+
211+
/// <summary>
212+
/// 测试 - 1900-01-01 的时间序列化为 null 后反序列化应还原为 1900-01-01
213+
/// </summary>
214+
[Fact]
215+
public void RoundTrip_Serialization_Deserialization_ShouldMaintainSemantics()
216+
{
217+
var original = new JsonDateTimeSample
218+
{
219+
ConfirmTime = DefaultDate,
220+
OptionalTime = null
221+
};
222+
223+
var json = JsonConvert.SerializeObject(original);
224+
var deserialized = JsonConvert.DeserializeObject<JsonDateTimeSample>(json);
225+
Output.WriteLine(json);
226+
Assert.Equal(DefaultDate, deserialized.ConfirmTime);
227+
Assert.Equal(DefaultDate, deserialized.OptionalTime);
228+
}
229+
230+
private class JsonDateTimeSample
231+
{
232+
[JsonConverter(typeof(DateTimeNullTo1900Converter))]
233+
public DateTime ConfirmTime { get; set; }
234+
235+
[JsonConverter(typeof(DateTimeNullTo1900Converter))]
236+
public DateTime? OptionalTime { get; set; }
237+
}
94238
}

0 commit comments

Comments
 (0)