在不同时区安排

Schedule in different time zone

我正在开发一个 Django 项目。

我想自动同步 classes。

我的代码:

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'

它适用于伦敦时区。

每个 class 都有不同的时区。我希望时间表根据 classes 的相关时区自动 运行。

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

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

此代码在 Django/Celery 部分未经测试,但思路如下:

  1. 将您的 Celery-Beat 的时间表更改为每 15 分钟 运行。这应该几乎涵盖 all the TZ offsets in existence 因为大多数是小时的倍数或半小时的倍数,只有少数情况是一刻钟的倍数(所以这个 15 分钟的决议应该涵盖 all 世界时区偏移量):

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

    在这一点上,Celery 的时区并不重要,因为我们将使用唯一的 decent 时区作为参考:UTC。

  2. 创建一个辅助函数,它将为您提供 现在 ("now" 意思是 "when your task is run") 是“almost”午夜。您的任务将 运行 每 15 分钟...可能在 15 分钟标记后几毫秒...所以让我们给它 10 分钟的缓冲时间(应该是这样,way 绰绰有余)。只要缓冲少于 15 分钟,你应该没问题(fine 意味着你不会有一个任务,下一个认为 "now" 是午夜,因此 运行 同步两次)

    这应该有帮助:

    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()) "probe"(或参考)更改为一些手动值,例如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()
    

请记住,在 夏令时 开关中,您可能最终会同步两次。