AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

TJSONMarshal / TJSONUnMarshal böse Falle

Ein Thema von Rollo62 · begonnen am 1. Okt 2017 · letzter Beitrag vom 3. Okt 2017
Antwort Antwort
Seite 1 von 2  1 2      
Rollo62

Registriert seit: 15. Mär 2007
4.093 Beiträge
 
Delphi 12 Athens
 
#1

TJSONMarshal / TJSONUnMarshal böse Falle

  Alt 1. Okt 2017, 21:40
Ich frage mich seit geraumen warum eine App plötzlich Timestamps falsch berechnet.
Der Grund war das Encoding / Decoding mit TJSONMarshal / TJSONUnMarshal.

Das hat bis dato gut funktioniert, Object zu String, und zurück, aber seit womöglich 10.1 Berlin gab es da plötzlich Probleme.
Normalerweise debugge ich nicht tief in die System Sourcen, aber hier musste es mal wieder sein

Der Grund war das TJSONMarshal / TJSONUnMarshal anscheinend neuerdings unterschiedliche IsDateTimeUTC settings per Default eingestellt haben.
Kann jetzt nicht genau sagen seit wann ...

Die Lösung war das explizit mit anzugeben, um die Konvertierungen kompatibel zu machen, also
LMar.DateTimeIsUTC := True; für Marshal/Unmarshal:

Delphi-Quellcode:
function TParcel.InternalMarshal_ToString : String;
var
  LMar : TJSONMarshal;
begin

  LMar := TJSONMarshal.Create(); // This doesn't correctly set DateTimeUTC by default

  try
      LMar.DateTimeIsUTC := True; // !!! Important to ensure same Coding/Decoding

      Result := LMar.Marshal(Self).ToString; // as TJSonObject;

  finally
      LMar.Free;
  end;

end;



function TParcel.InternalUnmarshal_FromObject(value: TJSONObject): TParcel;

var
  LMar: TJSONUnMarshal;

begin
    Result := nil;

    if not Assigned( value ) then
        Exit;

    LMar := TJSONUnMarshal.Create(); // This sets DateTimeIsUTC internally by default

    try
        LMar.DateTimeIsUTC := True; // !!! Important to ensure same Coding/Decoding

        ...
        ...
        ...


    finally
        LMar.Free;
    end;
end;

Wenn es nicht gleich gesetzt wird kann es zu einer Zeitdifferenz dei Encode/Decode kommen von 2:00h.
Das ist definitiv nicht das was ich erwarten würde

Rollo

Geändert von Rollo62 ( 1. Okt 2017 um 21:55 Uhr)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.158 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: TJSONMarshal / TJSONUnMarshal böse Falle

  Alt 2. Okt 2017, 08:39
Traue niemals der Delphi-RTL, schreibe Unit-Tests!

Zumindest in 10 Seattle ergibt ein EncodeDateTime(1988, 10, 21, 17, 45, 39, 999) im JSON noch ein '1988-10-21T17:45:39.999Z' .
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.452 Beiträge
 
Delphi 12 Athens
 
#3

AW: TJSONMarshal / TJSONUnMarshal böse Falle

  Alt 2. Okt 2017, 10:18
Kannst du dafür noch einen Eintrag in QP erstellen?
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.158 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: TJSONMarshal / TJSONUnMarshal böse Falle

  Alt 2. Okt 2017, 10:36
Ich verstehe das Problem noch nicht. Ein TDateTime ist lokale Zeit, nicht UTC. Von TObject nach JSON nehmen wir kein UTC an, von Json nach TObject schon. Ich denke, das ist doch so richtig, oder?

Delphi-Quellcode:
program UTCMarshalTest;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  System.DateUtils,
  System.Types,
  System.Json,
  REST.JsonReflect,
  Unit1 in 'Unit1.pas';

procedure p();
var
   marshal: TJsonMarshal;
   unmarshal: TJSONUnMarshal;
   myObject: TMyObject;
   timestamp: TDateTime;
   myObject2: TMyObject;
begin
   marshal := nil; unmarshal := nil;
   myObject := nil; myObject2 := nil;
   try
      marshal := TJSONMarshal.Create();
      unmarshal := TJSONUnMarshal.Create();

      myObject := TMyObject.Create();
      timestamp := EncodeDateTime(2017, 10, 02, 10, 28, 44, 123);
      myObject.FTimeStamp := timestamp;

      myObject2 := unmarshal.CreateObject(
         TMyObject,
         marshal.Marshal(myObject) as TJsonObject
      ) as TMyObject;

      Assert(
         CompareDateTime(myObject.FTimeStamp, myObject2.FTimeStamp)
         =
         System.Types.EqualsValue
      );
   finally
      marshal.Free(); unmarshal.Free();
      myObject.Free(); myObject2.Free();
   end;
end;

begin
   try
      p();
   except
      on E: Exception do
         Writeln(E.ClassName, ': ', E.Message);
   end;
   WriteLn(sLineBreak, 'end.');
   ReadLn;
end.

Geändert von Der schöne Günther ( 2. Okt 2017 um 10:39 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.452 Beiträge
 
Delphi 12 Athens
 
#5

AW: TJSONMarshal / TJSONUnMarshal böse Falle

  Alt 2. Okt 2017, 10:50
Das Problem ist, daß dein Code unter Tokyo eine EAssertionFailed-Exception auslöst.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.158 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: TJSONMarshal / TJSONUnMarshal böse Falle

  Alt 2. Okt 2017, 10:55
Oh, ok. Unter Seattle läuft alles korrekt durch. Ich dachte er sei verwirrt dass marshal und unmarshal nicht die gleiche Datums/UTC-Eigenschaften hatten.
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.093 Beiträge
 
Delphi 12 Athens
 
#7

AW: TJSONMarshal / TJSONUnMarshal böse Falle

  Alt 2. Okt 2017, 10:57
Hallo Uwe,

Zitat:
Kannst du dafür noch einen Eintrag in QP erstellen?
Bin mir nicht sicher ob das jetzt ein Bug ist oder nicht.
Man muss es halt "vollständig" konfigurieren.

Rollo
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.093 Beiträge
 
Delphi 12 Athens
 
#8

AW: TJSONMarshal / TJSONUnMarshal böse Falle

  Alt 2. Okt 2017, 11:04
Hallo Günther,

Zitat:
ch verstehe das Problem noch nicht. Ein TDateTime ist lokale Zeit, nicht UTC. Von TObject nach JSON nehmen wir kein UTC an, von Json nach TObject schon. Ich denke, das ist doch so richtig, oder?
Das Problem ist ich ein Objekt zu JSON mit Marshal encodiere , und
dann dieses JSON wieder zu einem Objekt mit Unmarshal dekodiere.

Wenn da im Objekt ein TDateTime Feld drin ist wird mit Marshal eine UTC Korrektur gemacht
und dann bei Unmarshal aber nicht (oder umgekehrt, habs jetzt gerade nicht nachgesehen).
Standardmässig wird das ISOEncode benutzt, welches UTC berücksichtigt.

Das Ergebnis-Objekt hat dann danach zum Ausgangs-Objekt je nach Zeitzone eine Differenz von z.B. +2:00.

Es muss im Marshal/Umarshal DateTimeIsUTC = True/False; expliziert gesetzt werden das ich mit oder ohne Korrektur arbeiten möchte, jedenfalls das es bei Beiden gleich sein sollte.

Rollo

Geändert von Rollo62 ( 2. Okt 2017 um 11:06 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.452 Beiträge
 
Delphi 12 Athens
 
#9

AW: TJSONMarshal / TJSONUnMarshal böse Falle

  Alt 2. Okt 2017, 11:20
Bin mir nicht sicher ob das jetzt ein Bug ist oder nicht.
Man muss es halt "vollständig" konfigurieren.
Das Verhalten unter Tokyo ist zumindest ein Anderes als unter Seattle und Berlin. Das ist in jedem Fall einen QP-Eintrag wert (Regression). Der Fehler kommt durch einen Bugfix in TISODateTimeInterceptor zustande, der eine entsprechende Anpassung in TJSONMarshal.Create erfordert. Insofern ist dein Anwendungsfall ein wichtiger Testcase.

Berlin:
Delphi-Quellcode:
constructor TISODateTimeInterceptor.Create(ADateTimeIsUTC: Boolean);
begin
  ConverterType := ctString;
  ReverterType := rtString;
  FDateTimeIsUTC := true;
end;
Tokyo:
Delphi-Quellcode:
constructor TISODateTimeInterceptor.Create(ADateTimeIsUTC: Boolean);
begin
  ConverterType := ctString;
  ReverterType := rtString;
  FDateTimeIsUTC := ADateTimeIsUTC;
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.093 Beiträge
 
Delphi 12 Athens
 
#10

AW: TJSONMarshal / TJSONUnMarshal böse Falle

  Alt 2. Okt 2017, 18:02
Hallo Uwe,

hier der QP-Eintrag, hab mal ne freie Minute gefunden.

Rollo
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:41 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz