Search code examples
djangocelerycelerybeat

Celery beat_schedule using wrong timezone


I am trying to run a daily task as part of my Django web application using celery beat, which calls a function with a date string argument. The beat schedule works fine and calls the function at the right time each day, but the date string inputted to the function is always one day behind. I assume this is because the timezone setting is wrong, but I think I have configured Django and celery correctly so I can't see where the problem is.

Relevant settings in ./settings.py:

TIME_ZONE = 'Europe/London'
USE_TZ = True
CELERY_ENABLE_UTC = False
CELERY_TIMEZONE = TIME_ZONE

My celery config in ./my_project/celery.py:

from django.utils import timezone
from celery import Celery
from celery.schedules import crontab


app = Celery('my_project')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

# Configure daily tasks
app.conf.beat_schedule = {
    # Executes `my_task` every day at 10:00am
    'do-my-task': {
        'task': 'tasks.tasks.my_task',
        'schedule': crontab(minute=0, hour=10),
        'args': (timezone.now().strftime('%d/%m/%Y'), ),
    },
}

Any ideas why this should be inputting the wrong date string as the argument to my_task?


Solution

  • django.utils.timezone.now does not do what you think it does. According to the docs it will return the time in UTC with the timezone set to UTC. It will not return the time in Europe/London as you want:

    If USE_TZ is True, this will be an aware datetime representing the current time in UTC. Note that now() will always return times in UTC regardless of the value of TIME_ZONE; you can use localtime() to get the time in the current time zone.

    As the docs suggest, use localtime instead of now.