我正在尝试使用TJSONObjectBuilder...AddPairs()
解析扩展的JSON。我的JSON包含一个$date
(MongoDB需要它)。但是无论我如何尝试,时区都会中断。
Input : {"Zulu":{"$date":"2019-01-01T00:00:00.000Z"},"Utc+1":{"$date":"2019-01-01T01:00:00.000+01:00"}}
Output: {"Zulu":{"$date":"2019-01-01T01:00:00.000Z"},"Utc+1":{"$date":"2019-01-01T01:00:00.000Z"}}
^ ^
没有TJsonDateTimeZoneHandling.Utc
,它起作用:
Output: {"Zulu":{"$date":"2019-01-01T01:00:00.000+01:00"},"Utc+1":{"$date":"2019-01-01T01:00:00.000+01:00"}}
这是我显示的最小代码:
program SystemJsonDateTest;
{$APPTYPE CONSOLE}
uses
System.Classes, System.JSON.Types, System.JSON.Writers, System.JSON.Builders;
var
StringWriter: TStringWriter;
JsonWriter: TJsonTextWriter;
Builder: TJSONObjectBuilder;
begin
StringWriter:= TStringWriter.Create;
JsonWriter:= TJsonTextWriter.Create(StringWriter);
JsonWriter.ExtendedJsonMode:= TJsonExtendedJsonMode.StrictMode;
JsonWriter.DateTimeZoneHandling:= TJsonDateTimeZoneHandling.Utc;
TJSONObjectBuilder.Create(JsonWriter)
.BeginObject
.AddPairs('{"Zulu":{"$date":"2019-01-01T00:00:00.000Z"},"Utc+1":{"$date":"2019-01-01T01:00:00.000+01:00"}}')
.EndObject
.Free;
JsonWriter.Free;
WriteLn(StringWriter.ToString);
StringWriter.Free;
ReadLn;
end.
背景:我正在使用TMongoDocument.AsJSON
,发现了此现象,并尝试用最少的代码重现它。如果我做的事情很奇怪或者可以简化,请发表评论...
在那个MongoDocument中,使用了TBsonWriter
,但它显示了相同的问题:
Stream:= TFileStream.Create('file.bson', fmCreate);
BsonWriter:= TBsonWriter.Create(Stream);
TJSONObjectBuilder.Create(BsonWriter).BeginObject.AddPairs(//see above
[IIRC MongoDB预期不支持Date
字段的“ $ date”扩展语法中的区域。
[reference documentation states的Date
值存储为UTC-它们甚至以BSON格式被称为UTC Date
,并存储为Int64的Unix毫秒数:
BSON Date是一个64位整数,代表自Unix纪元(1970年1月1日)以来的毫秒数。这导致过去和将来的可表示日期范围约为2.9亿年。
因此,最好只将UTC日期发送到MongoDB,并在客户端进行转换。即使转换正确,在任何情况下您都将丢失区域信息,因为它将存储为UTC。
BTW,最好只在任何类型的数据库中使用UTC日期,然后在显示/报告时使用即时转换为当前用户本地,并将本地区域存储在单独的字段中(如果确实需要) 。