0

I have a simple Group model:

class Group(models.Model):
   leader = models.ForeignKey(User, on_delete=models.CASCADE)
   name = models.CharField(max_length=55)
   description = models.TextField()
   joined = models.ManyToManyField(User, blank=True)
   start_time = models.TimeField(null=True)
   end_time = models.TimeField(null=True)
   email_list = ArrayField(
        models.CharField(max_length=255, blank=True),
        blank=True,
        default=list,
    )
    DAYS = [
        ('Sundays', 'Sundays'),
        ('Mondays', 'Mondays'),
        ('Tuesdays', 'Tuesdays'),
        ('Wednesdays', 'Wednesdays'),
        ('Thursdays', 'Thursdays'),
        ('Fridays', 'Fridays'),
        ('Saturdays', 'Saturday7'),
    ]
    meeting_day = MultiSelectField(
        verbose_name = 'Meeting day(s)',
        choices=DAYS,
        max_choices=7,
        max_length=255
    )

When Users create a Group, they are required to choose a start time. I have this celery periodic task that runs every minute, checking if a Group is 30 minutes from starting to send notifications to everyone on the email_list.

The issue I'm having is that the time the User inputs is always off. If the User wants their Group to start at 9:00AM, it gets saved on the database at 13:00, and the celery task gets sent out at the wrong time.

I have UTC set to true in my settings file so I assumed that it's universal, as in whatever the time the User chooses will be saved in UTC time which may look different, but is still synced up.

Here's my beat schedule:

app.conf.beat_schedule = {
    'start_group_notification': {
        'task': 'start_group_notification_task',
        'schedule': crontab(),
    }
}

and here's the task:

@shared_task(name='start_group_notification_task')
def start_group_notification_task():
    thirty_minutes_from_now = datetime.datetime.now() + datetime.timedelta(minutes=30)
    chaburahs = Group.objects.filter(
        start_time__hour=thirty_minutes_from_now.hour, 
        start_time__minute=thirty_minutes_from_now.minute
    ).prefetch_related("joined")
    for group in groups: 
        for email in group.email_list:
            send_mail (
                    'group starting in 30 minutes',
                    group.name,
                    NOTIFICATION_EMAIL,
                    [email],
                    fail_silently=False
                )

What I want is pretty simple, but I don't know how to fix it since I don't really know what the problem is. Maybe I don't understand UTC, but when a User creates a Group that should start at 9:00AM EST, no matter which time zone a joined User is, it will start at 9:00AM EST. Granted for the User it might be a different time, but it'll always start at 9:00AM EST. So, I don't get why the model isn't being filtered and the task isn't being sent if the time is saved in UTC.

Last thing, my django admin says that my time fields are 'four hours ahead of server time' but I'm not sure if thats UTC or something else.

Yehuda
  • 27
  • 15
  • The basic issue here is that `TimeFields` don't support time zones, only `DateTimeFields` do. Having time-zone-aware times without dates is generally considered to be an incoherent concept (for example, a given time might not happen on some days, or might happen twice), so are often not supported. You might need to rethink your data model. – Kevin Christopher Henry Aug 14 '22 at 14:39
  • just edited to show more of my model, the issue is that the creator chooses days of the week not dates. The date to the creator of the Group doesn't really matter. – Yehuda Aug 14 '22 at 14:47
  • Sure, but this way of modeling the situation isn't supported by Django's automatic time zone conversions ([since](https://docs.djangoproject.com/en/4.0/topics/i18n/timezones/#naive-and-aware-datetime-objects) "a timezone for a time with no associated date does not make sense."). One alternative is to store the times, days of the week, and time zone separately and then construct a specific time-zone-aware datetime when you need it. Another is to store the times using `DateTimeFields` (with an arbitrary date) and then take that limitation into account with your filtering, etc. – Kevin Christopher Henry Aug 14 '22 at 15:33

0 Answers0