I'm trying to parse extended JSON using TJSONObjectBuilder...AddPairs()
. My JSON contains a $date
(I need it in Utc for MongoDB). But somehow the timezone gets broken, no matter if my input is already Utc or not.
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"}}
^ ^
Without TJsonDateTimeZoneHandling.Utc
it is correct, but that doesn't help me, because I need the result in Utc:
Output: {"Zulu":{"$date":"2019-01-01T01:00:00.000+01:00"},"Utc+1":{"$date":"2019-01-01T01:00:00.000+01:00"}}
Here is my minimal code to show it:
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"},'
+ '"Unix":{"$date":1546300800000}}')
.EndObject
.Free;
JsonWriter.Free;
WriteLn(StringWriter.ToString);
StringWriter.Free;
ReadLn;
end.
Background: I'm using TMongoDocument.AsJSON
, found this behavior and tried to reproduce it with minimal code and without any reference to MongoDB components. If I'm doing something weird or the demo can be even more simplified, please comment...
In that MongoDocument, TBsonWriter
is used instead, but it shows the same problem:
Stream:= TFileStream.Create('file.bson', fmCreate);
BsonWriter:= TBsonWriter.Create(Stream);
TJSONObjectBuilder.Create(BsonWriter).BeginObject.AddPairs(//see above
I know, this was a lot of text - in case you forgot the question, it is in the title ;)
Yes, it is a bug, and it is fixed in 10.3.
In unit System.JSON.Builders, TJSONCollectionBuilder.TBaseCollection.WriteJSON()
creates a TJsonTextReader with the default DateTimeZoneHandling=Local, which means, any DateTimes are converted to local.
But in System.JSON.Writers, TJsonTextWriter.WriteValue(Value: TDateTime)
, the DateTime value, which cannot contain the time zone, is expected and interpreted as Utc when DateTimeZoneHandling=Utc.
So, TJSONCollectionBuilder requires a Writer with DateTimeZoneHandling=Local, which makes it impossible to get the output in correct Utc.
...and just after debugging this, I knew what to google for: http://docwiki.embarcadero.com/RADStudio/Rio/en/New_features_and_customer_reported_issues_fixed_in_RAD_Studio_10.3