celery / django-celery-beat

Celery Periodic Tasks backed by the Django ORM
Other
1.7k stars 429 forks source link

bug USE_TZ = False TIME_ZONE = 'Asia/Shanghai' raise TypeError: can't compare offset-naive and offset-aware datetimes #801

Open ChanXing2023 opened 2 months ago

ChanXing2023 commented 2 months ago

Summary:

Include a brief description of the problem here, and fill out the version info below.

Celery Version: 5.4.0 Celery-Beat Version: 2.7.0

Exact steps to reproduce the issue:

  1. settings.py
    
    LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_TZ = False

DJANGO_CELERY_BEAT_TZ_AWARE = True

3. raise  TypeError: can't compare offset-naive and offset-aware datetimes 
Code fixes
def is_due(self):
    if not self.model.enabled:
        # 5 second delay for re-enable.
        return schedules.schedstate(False, 5.0)

    # START DATE: only run after the `start_time`, if one exists.
    if self.model.start_time is not None:
        now = self._default_now()
        if getattr(settings, 'DJANGO_CELERY_BEAT_TZ_AWARE', True):
            now = maybe_make_aware(self._default_now())
        if self.model.start_time.tzinfo is None:
            if now.tzinfo is not None:
              now=now.replace(tzinfo=None)
After adding the code it works fine
        if self.model.start_time.tzinfo is None:
            if now.tzinfo is not None:
              now=now.replace(tzinfo=None)
but save data raise error

MySQL backend does not support timezone-aware datetimes when USE_TZ is False.

to solve this bug, add the following code
def save(self):
    # Object may not be synchronized, so only
    # change the fields we care about.
    obj = type(self.model)._default_manager.get(pk=self.model.pk)
    for field in self.save_fields:
        setattr(obj, field, getattr(self.model, field))
    if obj.start_time and obj.start_time.tzinfo:
        obj.start_time=obj.start_time.replace(tzinfo=None)
    if obj.last_run_at and obj.last_run_at.tzinfo:
        obj.last_run_at=obj.last_run_at.replace(tzinfo=None)
    if hasattr(obj,'data_changed') and getattr(obj,'data_changed').tzinfo:
        obj.data_changed=obj.data_changed.replace(tzinfo=None)
    obj.save()


### Detailed information

Please include more detailed information here, such as relevant information about your system setup, things you did to try and debug the problem, log messages, etc.  
jmartins-sh commented 2 months ago

Hey @ChanXing2023, how's it going? Is there any workaround besides update the lib's code?

ChanXing2023 commented 2 months ago

only update the lib's code