How to serialize dates as UTC?

utc
date
serialization
delphi
(Alexander Pustotin) #1

Hello

my server has to works with date-time values in the UTC format.
However, when the date-time value is being serialized the DateTimeToSOAPDateTime method formats its string as:

yyyy-mm-ddThh:nn:ss (e.g. 2018-04-19T10:00:00)

Such string is treated by the client JavaScript code as a local date-time value. It would be taken as UTC in case of “Z” at the end of the string e.g.

'2018-04-19T10:00:00Z’.

Question:
What is a right approach to serialize dates as UTC?

I use RemObjects SDK v9.4.0.1361.

regards

(EvgenyK) #2

use XSDateTime datatype instead of DateTime

(Alexander Pustotin) #3

Hello Evgeny

Thank you for the feedback.

I checked XsDateTime and found out that “xsDateTime” converts to “date-time” in JSON. It means that all API client code generated on the base of the JSON won’t differ XsDateTime and DateTime. It leads to unexpected working of methods XsDateTime.WriteComplex/XsDateTime.ReadComplex.

Did I miss a right workflow?

regards

(EvgenyK) #4

the main difference: Datetime doesn’t contain offset part, but XSDateTime - contains.
as a result, offset part (Z) is supported only in XSDateTime.

so if you want to read/write the offset part on Delphi side - use XSDateTime

(Alexander Pustotin) #5

I see the difference but I don’t see how it works in non-Delphi environment (Angular, JavaScript) where API client code is generated from the API JSON?

(RemObjects) #6

Thanks, logged as bugs://80004

(RemObjects) #7

bugs://80004 got closed with status fixed.

(EvgenyK) #10

pls update these files:

uROJSONMessage.pas
  TROJSONMessage = class(TROMessage)
  private
    fSerializeDateTimeinUTC: Boolean;  //added
  published
    property SerializeDateTimeinUTC: Boolean read fSerializeDateTimeinUTC write fSerializeDateTimeinUTC default False;  //added
...
procedure TROJSONSerializer.ReadDateTime(const aName: string; var Ref;
  ArrayElementId: integer);
..
  if EndsWith('Z', lItem.AsString) then
    TDateTime(Ref) := UTCDateTimeToLocalDateTime(SOAPDateTimeToDateTime(lItem.AsString, lOffset))
  else
    TDateTime(Ref) := SOAPDateTimeToDateTime(lItem.AsString, lOffset);
end;
...
procedure TROJSONSerializer.WriteDateTime(const aName: string; const Ref;
  ArrayElementId: integer);
begin
  if fOwner.fSerializeDateTimeinUTC then
    IntWriteObject(aName, DateTimeToSOAPDateTime(LocalDateTimeToUTCDateTime(TDateTime(Ref)))+'Z')
  else
    IntWriteObject(aName, DateTimeToSOAPDateTime(TDateTime(Ref)));
end;
...
procedure TROJSONMessage.Assign(Source: TPersistent);
...
    SerializeDateTimeinUTC := lSource.SerializeDateTimeinUTC;
...
end;
uROHttpApiDispatcher.pas
procedure TROHttpApiDispatcher.InvokeServiceMethod(aTransport: IROHTTPTransport;aRequest: IROHttpRequest;
  aResponse: IROHttpResponse; aRequestData, aResponseData: TStream);
...
begin
  l_JsonMessage := TROJSONMessage.Create;
  try
    l_JsonMessage.SerializeDateTimeinUTC := True; //added
(Alexander Pustotin) #11

thank you, Evgeny.

(Benjamin Keffer) #12

This should be optional. Could you implement this?

(EvgenyK) #13

what problems you have with this fix?
UTC format of date-times is standard: https://www.w3schools.com/xml/schema_dtypes_date.asp