From 46bd710128596d4dc7f6e731cd0ce73a7a282923 Mon Sep 17 00:00:00 2001 From: xRain Date: Fri, 21 Aug 2026 04:09:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20JsonWriter/JsonReader=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20DateTime=20=E5=AD=97=E6=AE=B5(=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E5=8C=96=E4=B8=BA=20yyyy-MM-dd=20HH:mm:ss=20=E5=AD=97=E7=AC=A6?= =?UTF-8?q?=E4=B8=B2,=E5=8F=AF=E5=8F=8D=E5=BA=8F=E5=88=97=E5=8C=96?= =?UTF-8?q?=E5=9B=9E,=E5=90=AB=20Option)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 ++++- src/json/JsonReader.cj | 12 +++++++++++ src/json/JsonWriter.cj | 2 ++ src/tests/JsonSerializer_test.cj | 37 ++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ec8ef60..eaf83fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ target/ -*.cj.macrocall \ No newline at end of file +*.cj.macrocall +# 宏编译产物(构建时自动生成,不入库) +src/macros/*.cjo +src/macros/*.dll diff --git a/src/json/JsonReader.cj b/src/json/JsonReader.cj index 6f29c3f..7e6a42f 100644 --- a/src/json/JsonReader.cj +++ b/src/json/JsonReader.cj @@ -12,6 +12,7 @@ package simcu::serialization.json import std.collection.* import std.convert.* import std.reflect.* +import std.time.* import stdx.encoding.json.* import simcu::serialization.common.ReflectionCache import simcu::serialization.common.FieldMetadata @@ -62,6 +63,7 @@ public class JsonReader { case "Float64" => return readFloat64(value) case "Float32" => return Float32(readFloat64(value)) case "Rune" => return readChar(value) + case "DateTime" | "std.time.DateTime" => return readDateTime(value) case _ => () } @@ -298,6 +300,15 @@ public class JsonReader { throw Exception("JsonSerializer: 无法转换为 Char") } + private static func readDateTime(v: JsonValue): DateTime { + let s = readString(v) + try { + return DateTime.parse(s, "yyyy-MM-dd HH:mm:ss") + } catch (_: Exception) { + throw Exception("JsonSerializer: 无法转换为 DateTime: ${s}") + } + } + /// 生成某类型的占位默认值(用于构造 Option 的 None:None 的参数槽类型是 X)。 private static func defaultValueFor(typeName: String): Any { match (typeName) { @@ -314,6 +325,7 @@ public class JsonReader { case "Float64" => return Float64(0.0) case "Float32" => return Float32(0.0) case "Rune" => return Rune(0) + case "DateTime" | "std.time.DateTime" => return DateTime.parse("1970-01-01 00:00:00", "yyyy-MM-dd HH:mm:ss") case _ => () } // 集合/对象/枚举:反射无参构造;失败则抛异常 diff --git a/src/json/JsonWriter.cj b/src/json/JsonWriter.cj index af7f6e9..09aefb7 100644 --- a/src/json/JsonWriter.cj +++ b/src/json/JsonWriter.cj @@ -10,6 +10,7 @@ package simcu::serialization.json import std.collection.* import std.reflect.* +import std.time.* import stdx.encoding.json.* import simcu::serialization.common.ReflectionCache import simcu::serialization.common.FieldMetadata @@ -42,6 +43,7 @@ public class JsonWriter { if (let u64: UInt64 <- value) { return JsonInt(Int64(u64)) } if (let f32: Float32 <- value) { return JsonFloat(Float64(f32)) } if (let c: Rune <- value) { return JsonString("${c}") } + if (let dt: DateTime <- value) { return JsonString(dt.format("yyyy-MM-dd HH:mm:ss")) } let typeName = TypeInfo.of(value).toString() diff --git a/src/tests/JsonSerializer_test.cj b/src/tests/JsonSerializer_test.cj index 820cd98..51f0467 100644 --- a/src/tests/JsonSerializer_test.cj +++ b/src/tests/JsonSerializer_test.cj @@ -11,6 +11,7 @@ package simcu::serialization.tests import std.collection.* +import std.time.* import std.unittest.* import std.unittest.testmacro.* import simcu::serialization.* @@ -55,6 +56,13 @@ class User <: BaseUser { public var temp: String = "secret" // 无下划线 + 忽略 } +// DateTime 字段测试实体 +class Event { + public var _name: String = "" + public var _time: DateTime = DateTime.parse("1970-01-01 00:00:00", "yyyy-MM-dd HH:mm:ss") + public var _optTime: ?DateTime = None +} + // 多层继承:爷(标宏)→ 父(不标宏)→ 子 @SerializerParent open class GrandParent { @@ -304,6 +312,35 @@ public class JsonSerializerTests { } } + /// DateTime:输出 yyyy-MM-dd HH:mm:ss 字符串并可反序列化回 + @TestCase + public func dateTimeRoundTrip(): Unit { + let e = Event() + e._name = "login" + e._time = DateTime.parse("2026-08-21 02:27:48", "yyyy-MM-dd HH:mm:ss") + e._optTime = Some(DateTime.parse("2026-01-02 03:04:05", "yyyy-MM-dd HH:mm:ss")) + let json = JsonSerializer.Serialize(e) + @Expect(json.contains("\"_time\": \"2026-08-21 02:27:48\""), true) + @Expect(json.contains("\"_optTime\": \"2026-01-02 03:04:05\""), true) + let back = JsonSerializer.Deserialize(json) + @Expect(back._time.format("yyyy-MM-dd HH:mm:ss"), "2026-08-21 02:27:48") + let optVal: ?DateTime = back._optTime + @Expect(optVal.isSome(), true) + if (let Some(dt) <- optVal) { + @Expect(dt.format("yyyy-MM-dd HH:mm:ss"), "2026-01-02 03:04:05") + } + // 顶层 DateTime 直接序列化 + @Expect(JsonSerializer.Serialize(back._time), "\"2026-08-21 02:27:48\"") + // Option None → null + let e2 = Event() + e2._name = "n" + e2._time = DateTime.parse("2026-01-01 00:00:00", "yyyy-MM-dd HH:mm:ss") + let json2 = JsonSerializer.Serialize(e2) + @Expect(json2.contains("\"_optTime\": null"), true) + let back2 = JsonSerializer.Deserialize(json2) + @Expect(back2._optTime.isNone(), true) + } + /// 宽松类型转换:JSON 数字 ↔ 字符串字段互转 @TestCase public func looseConversion(): Unit {