安排在不同的时区

时间:2018-01-04 05:50:36

标签: python django timezone celerybeat

我正在开发一个Django项目。

我想自动同步课程。

我的代码:

from datetime import timedelta
from celery.schedules import crontab

CELERYBEAT_SCHEDULE = {
'sync-classes': {
    'task': 'scheduler.tasks.sync_classes',
    'schedule': crontab(hour='0', minute=0),
}

CELERY_ENABLE_UTC = False
CELERY_TIMEZONE = 'Europe/London'

它适用于伦敦时区。

每个班级都有不同的时区。我希望计划根据类的相关时区自动运行。

sync_classes()方法中,我获取所有课程并在伦敦时区同步。

问题:如何根据时区同步每个班级?

1 个答案:

答案 0 :(得分:2)

这个代码在Django / Celery部分未经测试,但是这里的想法是:

  1. 将Celery-Beat的计划更改为每15分钟运行一次。这应该涵盖all the TZ offsets in existence,因为大多数是小时的倍数,或半小时的倍数,只有少数情况是四分之一小时的倍数(因此这15分钟的分辨率应涵盖 all < / em>世界的时区偏移量):

    CELERYBEAT_SCHEDULE = {
        'sync-classes': {
        'task': 'scheduler.tasks.sync_classes',
        'schedule': crontab(minute='*/15'),
    }
    
    CELERY_ENABLE_UTC = False   
    CELERY_TIMEZONE = 'Europe/London'
    

    此时,Celery的时区并不重要,因为我们将使用唯一的体面时区作为参考:UTC。

  2. 创建一个辅助功能,为您提供现在的时区名称(&#34;现在&#34; 意味着& #34;当你的任务运行时,#34; )几乎是&#34;午夜。你的任务将每15分钟运行一次...也许在15分钟后几毫秒...所以让我们给它10分钟的缓冲区(应该是这样,方式超过足够)。只要缓冲区少于15分钟,你应该没问题(罚款意味着你没有赢得一项任务而下一次认为&#34;现在&#34 ; 是午夜,因此两次运行同步)

    这应该有所帮助:

    import pytz
    import datetime
    
    utc_now = pytz.utc.localize(datetime.datetime.utcnow())
    collected_tz_names = []
    for tz in pytz.all_timezones_set:
        test_dt = utc_now.astimezone(pytz.timezone(tz))
        print("tz: %s, test_dt.time() %s" % (tz, test_dt.time()))
        is_midnight = (
            datetime.time(hour=0, minute=0, second=0) <=
            test_dt.time() <=
            datetime.time(hour=0, minute=10, second=0)
        )
        if is_midnight:
            collected_tz_names.append(tz)
    print("collected %s" % collected_tz_names)
    

    如果您想测试它,请更改utc_now = pytz.utc.localize(datetime.datetime.utcnow())&#34;探测&#34; (或引用)一些手动值,例如utc_now = pytz.utc.localize(datetime.datetime(year=2018, month=1, day=4, hour=4, minute=1, second=0)

  3. 一旦您收集了now列表中 collected_tz_names 午夜的时区,请运行同步方法。让我们说你需要同步的对象是User(s),对吧?并且您的User模型具有属性tz_name,该属性指示每个用户的时区。在这种情况下,这应该做:

    for user in User.objects.filter(tz_name__in=collected_tz_names):
        user.synchronize()
    
  4. 请注意,在夏令时切换中,您可能最终会同步两次。