REST and DateTime JSON values: how to set/get timezone info?

Hello,

I haven’t found much info about handling times when receiving them via a REST API, using JSON, and/or sending them back to the client.

Is there any way to define a “default” timezone for when the JSON value does not include the TZ information? And also, to return the time values tagged with a specific timezone?

Thanks!

I think DateTime values, in Remoting SDK, are essentially timezone-less (even though, as you say, in Json in theory that info could be encoded, n it cant be, in other protocols), meaning it is up to you to decide how to interpret them, as part of your logical interface definition.

Usually I suggest to always treat all dates as UTC / always use use UTC dates everywhere, and only convert locally, for display (e.g. based on the suers location, or other releant context (eg, an appointment for a phone call might make sense to convert to the user’s locale; the time for a convert might make sense to show in the time zone for the location event (stored/passed as separate value), but on both cases the actual DateTime would, on the server, be stored as UTC (and transmitted to/from clients as UTC).

But ofc thats just one way to do it.

hth,
marc

Hello Marc,

Thanks for your comments.

I’ve always handled the DateTime values as timezone-less, and it has worked fine. My apps do use dates and times heavily, but they always are “locally referenced”, if that makes sense. I haven’t had to think about TZ before. As far as I can see, to begin with, there is no TZ info on the TDateTime structure in Delphi, so no easy way to handle that directly in a Delphi app.

Now that we are opening the app to other clients, using a REST API, is where we are finding this problem. The client sends the data, as far as I can see, without any TZ info, but we receive a modified value. Or viceversa.

I haven’t done much tests myself, I’m only interpreting what I can see from the logs and the comments from the users. It might be that the client is actually sending some TZ info that is misinterpreted or something like that when converting the value from JSON to Delphi/C++Builder values, but for what they have sent me as examples, I don’t see any TZ tagging on the strings.

Anyway, I’ll try to make some more tests to identify exactly where the problem might be.

Thanks!

Thats the best approach, yes.

It’s seems like to start with, you need to sort out why non-RO client updates/changes the date time values. Is it because thye have a misunderstanding on what timezone it is or whether they should convert to a different timezone, when sending data back?

That could be an option, yes, that RO/Dlephi (or RO in general does have a bug where it misbehaves if a received date time string is not in the format it expects, but…

it sound like that is not the case.

It would be good to have the following four pieces off data for one (or more) “sample” failed request(s):

  • the actual datetime the server sent
  • how ROSDK sent it as Json string
  • what JSON it received back
  • the datetime vlaue that ROSDK made of this Json string

this way, we can narrow down which step failed (most likely between 2 and 3 (could be a non-ROSDK client bug/or misunderstanding), but; but possibly between 3 and 4 (with could be an ROSDK bug)…

Hi,

Delphi TROHttpApiDispatcher serializes TDateTime in UTC format.
Check:

procedure TROHttpApiDispatcher.InvokeServiceMethod(...);
..
  l_jsonMessage := TROHttpApiJSONMessage.Create;
  l_jsonMessage.SerializeDateTimeinUTC := True; //<<<<<<<<<

I assume your dates are not UTC, but a specific time zone, and this throws off the non-ROSDK client, as it treats them as/converts them from UTC?

Delphi uses usual TDateTime.

if this option is set, we convert local datetime to UTC one at serialization:

procedure TROJSONSerializer._WriteDateTime(const aName: string; aValue: TDateTime);
begin
  if fOwner.fSerializeDateTimeinUTC then
    IntWriteObject(aName, DateTimeToSOAPDateTime(LocalDateTimeToUTCDateTime(aValue)) + 'Z')
  else
    IntWriteObject(aName, DateTimeToSOAPDateTime(aValue));
end;

Thanks for the info, Evgeny and Marc.

My DateTimes are non UTC. As the clients we have made with RO are using the “native” RO protocols/transport, we haven’t had issues with conversions yet.

The problem is now with REST clients, and I assume the client library is doing the conversion from UTC (represented by the Z sent in the JSON message) to local time, and things break there.

I haven’t had the time to try directly from Postman or something similar to see what happens, but I do remember seeing the Z appended to the values when testing this. So I guess this is where the problem comes.

Evgeny, is there a way to control the SerializeDateTimeInUTC property at runtime from outside that method, InvokeServiceMethod?

Thanks!

Hi,

You can override DoOnActivate method.

code can be like

procedure TLoginService.DoOnActivate(aClientID: TGUID; const aMessage: IROMessage);
begin
  (aMessage as TROJSONMessage).SerializeDateTimeinUTC := False;
  inherited;
end;

Thank you.

Now… if only I can figure it out how to do that in C++Builder… :confused: a simple dynamic_cast didn’t work (doesn’t compile)

For what I could find, that construct is only valid in Delphi. There is no easy way to do that from C++Builder.

But you can do that in a small Delphi helper unit and call that from C++Builder:

unit UtileriasRODelphi;

interface

uses
  uROJSONMessage,
  uROClientIntf;

function ConvertirIROMessageAJSONMessage(const aMessage: IROMessage) : TROJSONMessage;

implementation

function ConvertirIROMessageAJSONMessage(const aMessage: IROMessage) : TROJSONMessage;
begin
	Result := (aMessage as TROJSONMessage);
end;

end.

I’m rebuilding to try this.

Thanks!

Sounds like the non-ROSDK client app nets to either be changed to use TC itself, or make sure to convert back to UTC when sending dates back to the server?

—marc

Hello Marc,

Yeah, they are sending the times tagged with a Z incorrectly for what I can see. But then I do return the times also with the Z when they do not represent UTC times…

Anyway, with this latest bit that Evgeny sent I can see that at least I am not returning the times with the Z in them, just need to try sending without that and see what happens. I’m just adding some methods to control this at runtime so I can easily try.

Thanks!

So, just the conclusion:

Disabling the conversion to UTC solves the problem of sending untagged times to the client, being converted to UTC when they should not be. Although, to be precise, the conversion was made correctly: from whatever local time zone is set on the machine running the RO Server, to UTC. The client was not interpreting correctly the timezone in this case, so the conversion caused them to receive a time that they did not expect.

This option does not disable the conversion in case the client SENDs the times tagged (with a Z, for instance). So that has to be solved on the client on the original request. Either they send the times correctly converted to UTC, or without any TZ tag.

Thanks for your help, Marc & Evgeny!

Oklay, that seems to clearly be a b ug in the client code then?

Happy to hear!