@zopyx (Andreas Jung) posted a new topic, subject "[plone.restapi] Dates and timezones". It read:

   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
    [code] 
        (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'
        
    [/code]
    
    They are created in Plone 5.2.2 as
    [code] 
        >>> 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>)
        
    [/code]
    
    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?

After which, @espenmn (Espen) added

    zopyx:
    
    > The event dates are also shown as `1 PM and 9 PM` .
    
    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
    
    github.com/plone/Products.CMFPlone
    
    ####  pickadate widget doesn't use the correct 24h format in some languages
    
    opened 03:37PM - 29 Jun 20 UTC
    
    closed 04:15PM - 29 Jun 20 UTC
    
    vincentfretin 
    
    BUG See https://community.plone.org/t/datetime-widget-format-not-am-pm/12491 What I did: Plone in French language, create a Page, click on the Dates tab and pick a date. What I expect...

Then @zopyx (Andreas Jung) said

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

After which, @zopyx (Andreas Jung) added

    I created an event through the Plone UI for `start=2020-11-13 9:00`. This is stored in Plone as
    [code] 
        datetime.datetime(2020, 11, 13, 9, 0, tzinfo=<DstTzInfo 'Europe/Amsterdam' CET+1:00:00 STD>)
        
    [/code]
    
    which is correct. So apparently something in plone.restapi appears to go wrong.

After which, @jaroel (Roel Bruggink) added

    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?

After which, @zopyx (Andreas Jung) added

    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
    [code] 
        "start": "2020-08-25T17:00:00+02:00"
        "start": "2020/08/25 17:00:00 GMT+2"
        
    [/code]
    
    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.

@zopyx (Andreas Jung) replied

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

@tisto (Tisto) replied

    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:
    
    github.com/plone/plone.app.event
    
    ####  Store UTC datetimes
    
    opened 09:32PM - 01 Jul 18 UTC
    
    thet 
    
    At the Bonn sprint we discussed options on fixing issues with plone.restapi and plone.app.event regarding timezone handling and storing date/time values...
    
    04 type: enhancement
    
      
    github.com/plone/plone.restapi
    
    ####  convert date/times to UTC when exporting, use python-datetime for parsing date strings
    
    `plone:master` ← `plone:thet-plone52`
    
    opened 10:51PM - 11 Feb 18 UTC
    
    thet 
    
    +84 -29
    
    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.

Then @thet (Johannes Raggam) said

    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:
    [code] 
        >>> 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()
        '2020-08-25T13:00:00+02:00'
        >>> app.Plone.e3.end.isoformat()
        '2020-08-25T21:00:00+02:00'
        >>> 
        
    [/code]
    
    collective.jsonify should serialize them by using `isoformat` as here (a `datetime` instance is an instance of `date`):  
    
    
    github.com
    
    #### collective/collective.jsonify/blob/3e259ccae6a50ebfdd24514ab5dcf9064f14571b/collective/jsonify/wrapper.py#L196
    [code]     
          186.             continue
        
        
          187.     value = _value
        
        
          188. 
        
          189. elif field_type == 'GeolocationField':
        
        
          190.     # super special plone.formwidget.geolocation case
        
        
          191.     self['latitude'] = getattr(value, 'latitude', 0)
        
        
          192.     self['longitude'] = getattr(value, 'longitude', 0)
        
        
          193.     continue
        
        
          194. 
        
          195. elif isinstance(value, date):
        
        
          196.     value = value.isoformat()
        
        
          197. 
        
          198. # elif field_type in ('TextLine',):
        
        
          199. else:
        
        
          200.     BASIC_TYPES = (
        
        
          201.         unicode, int, long, float, bool, type(None),
        
        
          202.         list, tuple, dict
        
        
          203.     )
        
        
          204.     if type(value) in BASIC_TYPES:
        
        
          205.         pass
        
        
          206.     else:
        
        
        
    [/code]
    
    Still, I suspect collective.jsonify to be the problem here. Can you give more context how or where this line comes from:
    [code] 
        (Pdb++) pp object_data['startDate']
        
    [/code]
    
    However, IMO collective.jsonify should convert the dates to UTC as plone.restapi does.

To which @zopyx (Andreas Jung) replied

    thet:
    
    > Still, I suspect collective.jsonify to be the problem here.
    
    That's my suspicion too...I will recheck with the next export on our side.

To which @erral (Mikel Larreategi) replied

    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:
    
    gist.github.com
    
    #### https://gist.github.com/gyst/c3739160a18cf52c93e0132da511b2ee
    
    ##### pytzfixer.py
    [code] 
        # coding=utf-8
        from zope.interface import classProvides, implements
        from collective.transmogrifier.interfaces import ISectionBlueprint
        from collective.transmogrifier.interfaces import ISection
        from collective.transmogrifier.utils import Matcher, Condition
        
        import logging
        logger = logging.getLogger(__name__)
        
        
    [/code]
    
    This file has been truncated. show original
    
    ##### pytzfixer.rst
    [code] 
        Pytz timezone fixer section
        ===========================
        
        This fixes the dreadful ``UnknownTimeZoneError: (UnknownTimeZoneError('GMT+1',)``
        thrown by ``transmogrify.dexterity.schemaupdater`` when writing Event dates.
        It turns out pytz does not recognize a timezone like ``GMT+1``.
        This should be ``Etc/GMT+1``. This blueprint fixes that8b7c:f320:99b9:690f:4595:cd17:293a:c069
        
          [pytzfixer]
          blueprint = quaive.transmogrifier.sections.pytz.fixer
    [/code]
    
    This file has been truncated. show original
    
    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:
    
    github.com
    
    #### codesyntax/bobtemplates.cs/blob/master/bobtemplates/cs/cs_migration/migration/blueprints/pytz_fixer.py
    [code] 
        # -*- coding: utf-8 -*-
        """
        Original: https://gist.github.com/gyst/c3739160a18cf52c93e0132da511b2ee
        
        see https://stackoverflow.com/questions/4008960/pytz-and-etc-gmt-5
        for GMT+ and GMT- bug
        """
        from collective.transmogrifier.interfaces import ISection
        from collective.transmogrifier.interfaces import ISectionBlueprint
        from collective.transmogrifier.utils import Condition
        from collective.transmogrifier.utils import Matcher
        from zope.interface import implementer
        from zope.interface import provider
        
        import logging
        
        
        logger = logging.getLogger(__name__)
        
        
        
    [/code]
    
    This file has been truncated. show original


{'source': 'discourse', 'url': 'https://community.plone.org/t/plone-restapi-dates-and-timezones/12774', 'title': '[plone.restapi] Dates and timezones', 'views': 513, 'has_accepted_answer': False, 'word_count': 872, 'like_count': 2, 'reply_count': 4, 'participant_count': 6, 'posts': 11, 'tags': '', 'author': '@zopyx (Andreas Jung)', 'participants': '@zopyx (Andreas Jung), @espenmn (Espen), @jaroel (Roel Bruggink), @tisto (Tisto), @thet (Johannes Raggam), @erral (Mikel Larreategi)', 'image_url': [None], 'created_at': '2020-08-24T14:56:44.718Z', 'last_posted_at': '2020-08-31T06:38:02.291Z'}