DEV Community

Dmitry Doroshev
Dmitry Doroshev

Posted on • Originally published at doroshev.substack.com

Calculating the next run date of a Celery periodic task

The problem

You have a periodic task in Celery defined with a crontab(...) schedule, and you want to calculate the next time it's supposed to run.

Example: you want to find out when crontab(hour=12, minute=0) will trigger next after now.

Simple, right? There’s croniter library, which seems to be designed to solve this exact problem. Just use it, right?

Well.

First mistake: trying croniter with crontab

So my first instinct was to use croniter like this:

from celery.schedules import crontab
from croniter import croniter
from datetime import datetime

schedule = crontab(hour=12, minute=0)
cron = croniter(schedule, datetime.now())
next_run = cron.get_next(datetime)
Enter fullscreen mode Exit fullscreen mode

Boom 💥 doesn’t work. Because Celery’s crontab is not a string and croniter expects a string like "0 12 * * *":

AttributeError: 'crontab' object has no attribute 'lower'
Enter fullscreen mode Exit fullscreen mode

And no, crontab() does not have a nice .as_cron_string() method either.

So now you’re stuck parsing crontab's internal fields (._orig_minute, ._orig_hour, etc) just to reconstruct a string - and it starts to smell like overengineering for something that should be simple.

The right way (which I learned too late)

Turns out Celery’s crontab (and all schedules derived from celery.schedules.BaseSchedule) already has a method for this:

from datetime import datetime
from celery.schedules import crontab

schedule = crontab(hour=12, minute=0)
now = datetime.now()
# `now` is datetime.datetime(2025, 6, 11, 0, 16, 58, 484085)
next_run = now + schedule.remaining_delta(now)[1]
# `next_run` is datetime.datetime(2025, 6, 11, 12, 0)
Enter fullscreen mode Exit fullscreen mode

That’s it. You don’t need croniter at all. Celery knows how to calculate the delta to the next run. It just doesn’t shout about it in the docs.

Summary

  • don’t reinvent Celery’s scheduling logic - it already has what you need;
  • crontab is not a cron string, don’t try to treat it like one;
  • use .remaining_delta(last_run) to calculate when the next run will happen.

Hope this saves someone the 2 hours I wasted trying to do it the wrong way.

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more