How fix this error : exchangelib.errors.InvalidTypeError: 'tzinfo' <UTC> must be of type <class 'exchangelib.ewsdatetime.EWSTimeZone'>

Question:

In my Django project, I have bump the Exchangelib version (3.2.1 to 4.9.0) and now an error occurs.
Traceback :

  File "/home/.../workspace/my_project/exchange_manager/models.py", line 297, in create_event
    event = self.create(*args, **kwargs)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/query.py", line 453, in create
    obj.save(force_insert=True, using=self.db)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/base.py", line 726, in save
    self.save_base(using=using, force_insert=force_insert,
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/base.py", line 763, in save_base
    updated = self._save_table(
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/base.py", line 868, in _save_table
    results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/base.py", line 906, in _do_insert
    return manager._insert(
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/query.py", line 1270, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1409, in execute_sql
    for sql, params in self.as_sql():
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1352, in as_sql
    value_rows = [
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1353, in <listcomp>
    [self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1353, in <listcomp>
    [self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1294, in prepare_value
    value = field.get_db_prep_save(value, connection=self.connection)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 842, in get_db_prep_save
    return self.get_db_prep_value(value, connection=connection, prepared=False)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 1428, in get_db_prep_value
    return connection.ops.adapt_datetimefield_value(value)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/db/backends/sqlite3/operations.py", line 247, in adapt_datetimefield_value
    value = timezone.make_naive(value, self.connection.timezone)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/django/utils/timezone.py", line 256, in make_naive
    return value.astimezone(timezone).replace(tzinfo=None)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/exchangelib/ewsdatetime.py", line 128, in astimezone
    t = super().astimezone(tz=tz).replace(tzinfo=tz)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/pytz/__init__.py", line 228, in fromutc
    return super(utc.__class__, self).fromutc(dt)
  File "/home/.../.local/share/virtualenvs/my_project-iOt348t5/lib/python3.8/site-packages/exchangelib/ewsdatetime.py", line 93, in __new__
    raise InvalidTypeError("tzinfo", tzinfo, EWSTimeZone)
exchangelib.errors.InvalidTypeError: 'tzinfo' <UTC> must be of type <class 'exchangelib.ewsdatetime.EWSTimeZone'>

Before the call of the create method, I use this code to transform timestamp to EWSDateTime instance.

LOCAL_TZ = pytz.timezone('Europe/Paris')
def timestamp_to_ews_datetime(timestamp):
    """
    Transform timestamp to EWSDateTime instance
    :param timestamp:
    :return:
    """
    temp_datetime = datetime.datetime.fromtimestamp(timestamp / 1000.0)
    temp_datetime = pytz.utc.localize(temp_datetime, is_dst=None).astimezone(LOCAL_TZ)
    return EWSDateTime.from_datetime(temp_datetime)

I have edit the LOCAL_TZ value but it does not works :

LOCAL_TZ = EWSTimeZone('Europe/Paris')

I don’t now if the problem is in this code.

Asked By: Guidev

||

Answers:

Thwas was answered in https://github.com/ecederstrand/exchangelib/issues/1140#issuecomment-1308814613:

When you’re trying to save an EWSDateTime to the database, the sqlite3 package is localizing datetime values to UTC and then removing the timezone info. EWSDateTime instances does not allow removing timezone info.

When you set the value on a Django model field, you should use a plain datetime object. The easiest way to convert from EWSDateTime to datetime is probably:

>>> from exchangelib import EWSDateTime, EWSTimeZone
>>> from datetime import datetime
>>> d = EWSDateTime(2013, 2, 1, tzinfo=EWSTimeZone.localzone())
>>> datetime(*d.timetuple()[:6], tzinfo=d.tzinfo)
datetime.datetime(2013, 1, 2, 0, 0, tzinfo=EWSTimeZone(key='Europe/Copenhagen'))
Answered By: Erik Cederstrand