[.Net Core 3.0+/.Net 5] System.Text.Json中時間格式化
阿新 • • 發佈:2020-11-13
### 簡介
.Net Core 3.0開始全新推出了一個名為`System.Text.Json`的Json解析庫,用於序列化和反序列化Json,此庫的設計是為了取代`Json.Net(Newtonsoft.Json)`
### 時間格式化的不足
`System.Text.Json`的優點就不說了,來說一下不完善的地方,畢竟一個新事物出來,不可能十全十美的,用的最多的就是時間的格式化
> 官方文件:在 System.Text.Json 中,具有內建支援的唯一格式是 **`ISO 8601-1:2019`**,因為它被廣泛採用、意義明確並且可精確地進行往返。 若要使用任何其他格式,請建立自定義轉換器
> **`ISO 8601-1:2019`**通俗的說就是時間格式化為**`2020-11-11T21:08:18`**。**`ISO 8601-1:2019`**標準參考:[ISO官網](https://www.iso.org/standard/70907.html) | [百度百科](https://baike.baidu.com/item/ISO%208601/3910715) | [wikipedia](https://en.wikipedia.org/wiki/ISO_8601)
但我們一般用的時候不想要這種格式,因為中間有一個`T`,前端處理起來很麻煩,最好還是返回指定的時間格式,例如:`yyyy-MM-dd`、`yyyy-MM-dd HH:mm:ss`。
### 解決方案
既然官方不內建提供指定時間格式化的方式,那就沒辦法了嗎,查閱文件發現,雖然無法簡單的實現功能,但是可以通過建立自定義轉換器來實現相應功能
文件地址:[微軟官方文件](https://docs.microsoft.com/zh-cn/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to#specify-date-format)
**以下是一個自定義時間轉化器的完整實現:**
```
public class DateTimeConverterUsingDateTimeParse : JsonConverter
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.Parse(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss"));
}
}
```
### 使用
程式碼看起來非常簡單是不是,只需要重寫`Read`和`Write`,但是我們只是寫了一個自定義轉換器,怎麼讓它生效呢,請往下看:
`JsonSerializer.Serialize()`和`JsonSerializer.Deserialize()`方法都接受一個`JsonSerializerOptions`型別的配置項引數
在`JsonSerializerOptions`新增`Converters`就可以了
```
JsonSerializerOptions options = new JsonSerializerOptions()
{
Converters.Add(new DateTimeConverterUsingDateTimeParse())
}
string jsonString = JsonSerializer.Serialize(data, options);
```
至此,我們已經實現使用`System.Text.Json`庫指定時間格式字串進行序列化和反序列化,你甚至可以把`yyyy-MM-dd HH:mm:ss`做成引數來更自由的指定格式化字串
### 基準測試
但是凡事有利就有弊,官方文件也說得很清楚了:
> 使用自定義轉換器與使用序列化程式的本機實現相比,此方法的效能大大降低
有人就想知道了,到底會影響多少效能呢,我進行了一項基準測試,序列化100000條資料,包含時間處理,模型如下:
```
public class Dto
{
public string Name { get; set; }
public string Phone { get; set; }
public DateTime DateTime { get; set; }
}
```
``` ini
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.100-rc.2.20479.15
[Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT [AttachedDebugger]
DefaultJob : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
System.Text.Json Version 5.0.0
Newtonsoft.Json Version 12.0.3
```
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------------------------- |----------:|---------:|---------:|----------:|----------:|---------:|----------:|
| SystemTextJsonConverterDate | 67.36 ms | 0.489 ms | 0.458 ms | 2250.0000 | 750.0000 | 750.0000 | 52.15 MB |
| SystemTextJson | 53.26 ms | 0.231 ms | 0.180 ms | 500.0000 | 500.0000 | 500.0000 | 48.67 MB |
| NewtonsoftJsonConverterDate | 123.42 ms | 1.847 ms | 1.727 ms | 5800.0000 | 2200.0000 | 600.0000 | 51.61 MB |
| NewtonsoftJson | 109.41 ms | 0.977 ms | 0.913 ms | 4800.0000 | 2000.0000 | 600.0000 | 50.82 MB |
### 結語
可以看到效能確實會有影響,但是可以忽略不計了,100000條才差10ms。
同時可以發現`System.Text.Json`效能是`Newtonsoft.Json`的兩倍
推薦大家以後在滿足需求的情況下儘量使用內建的`System.Text.Json`