[plone.restapi] Dates and timezones

We have some issues with events generated through plone.restapi and their dates and timezones.
The site TZ is set to Europe/Amsterdam. The start and end date of end event (coming from collective.jsonify) are

(Pdb++) pp object_data['startDate']
'2020/08/25 09:00:00 GMT+2'
(Pdb++) pp object_data['endDate']
'2020/08/25 17:00:00 GMT+2'

They are created in Plone 5.2.2 as

>>> doc.start
datetime.datetime(2020, 8, 25, 13, 0, tzinfo=<DstTzInfo 'Europe/Amsterdam' CEST+2:00:00 DST>)
>>> doc.end
datetime.datetime(2020, 8, 25, 21, 0, tzinfo=<DstTzInfo 'Europe/Amsterdam' CEST+2:00:00 DST>)

So there clearly visible some four hour offset (coming from the GMT+2 from the date data and perhaps the UTC+2 from the global timezone settings. The event dates are also shown as 1 PM and 9 PM.

Any trickery I am missing here?

About PM: Could this be related to translation of dates ?

In other words: in some (dutch).po-file there is a 'translation' of how dates are shown

The problem is not the display value but as said the improper 4 hour offset!

I created an event through the Plone UI for start=2020-11-13 9:00. This is stored in Plone as

datetime.datetime(2020, 11, 13, 9, 0, tzinfo=<DstTzInfo 'Europe/Amsterdam' CET+1:00:00 STD>)

which is correct. So apparently something in plone.restapi appears to go wrong.

The converter for datetime to json is here: https://github.com/plone/plone.restapi/blob/acdcc7435aeb7c0140c7e0fa4ab9c09d4592ba5b/src/plone/restapi/serializer/converters.py#L33-L54

It could very well be that we're converting the datetime from the site TZ to the local TZ (2H) and then to UTC (2H).

What happens if you set the site TZ to say +3 or -3? Do you still see a 4H difference?

Seems to be related to the format of the passed date string. I created a fresh Plone site with global TZ "Europe/Berlin". I created two events with dates

"start": "2020-08-25T17:00:00+02:00"
"start": "2020/08/25 17:00:00 GMT+2"

The event is rendered with Aug 25, 2020 05:00 PM ,
the second one renders as Aug 25, 2020 09:00 PM

Event #1 is correct (with the ISO-8601 format string). Obviously something is happening with the second date format. The second date string is clearly not an ISO-8601 date. If ISO-8601-only is expected, a compliance check and error would be helpful here.

"Solution" in our case: we subtract 4 hours upon import time :slight_smile:

1 Like

This is a pretty complex matter that we discussed quite a few times already. Sorry, I can not help right now with this particular issue. Here is the current state of affairs of datetime handling in plone.restapi and plone.app.event:

I would love to clean this up and maybe get the into Plone 6. Though, I guess this depends on @thet or someone else to step up to do the actual work.

1 Like

doc.start and doc.end in your initial example are correct, so the creation via plone.restapi looks like it's working as expected (except for the second example where you pass a non ISO-8601 string).

I've checked it by creating an event TTW:

>>> app.Plone.e3.start
datetime.datetime(2020, 8, 25, 13, 0, tzinfo=<DstTzInfo 'Europe/Amsterdam' CEST+2:00:00 DST>)
>>> app.Plone.e3.end
datetime.datetime(2020, 8, 25, 21, 0, tzinfo=<DstTzInfo 'Europe/Amsterdam' CEST+2:00:00 DST>)
>>> app.Plone.e3.start.isoformat()
>>> app.Plone.e3.end.isoformat()

collective.jsonify should serialize them by using isoformat as here (a datetime instance is an instance of date):

Still, I suspect collective.jsonify to be the problem here. Can you give more context how or where this line comes from:

(Pdb++) pp object_data['startDate']

However, IMO collective.jsonify should convert the dates to UTC as plone.restapi does.

That's my suspicion too...I will recheck with the next export on our side.

Some time ago we faced a similar problem with some of the datetime fields exported using collective.jsonify and imported with transmogrifier.

We found this gist that replaced all "GMT+X" timezones with "Etc/GMT+X" which promised to fix the problem:

Nevertheless we also saw that GMT+X was not Etc/GMT+X but Etc/GMT-X (see the comment on that gist)

So, we ended creating a transmogrifier blueprint for our imports with that code: