Search code examples
djangodjango-timezone

Why is timezone.now showing a future date when being applied as a default value to DateField in django


Here are the relevant settings in my project:

settings.py

TIME_ZONE = "US/Mountain"
USE_TZ = True

models.py (using timezone.now)

class Submission(models.Model):
    date_created = models.DateField(
        default=timezone.now,
        blank=True,
    )

    datetime_created = models.DateTimeField(
        default=timezone.now,
    )

If I create a Submission at 5PM MST on 03/01/2023 these are the values I get:

  • date_created: "2023-03-02"
  • datetime_created: "2023-03-01 17:00:00-07:00"

Why would date_created be using the date of the following date?


Solution

  • I think the reason this happens is because the "date" (without the time) isn't timezone aware.

    You can see in the DateField source where Django automatically converts a datetime back to UTC:

        def _check_fix_default_value(self):
            """
            Warn that using an actual date or datetime value is probably wrong;
            it's only evaluated on server startup.
            """
            if not self.has_default():
                return []
    
            value = self.default
            if isinstance(value, datetime.datetime):
                value = _to_naive(value).date()  # <————— HERE!
            elif isinstance(value, datetime.date):
                pass
            else:
                # No explicit date / datetime value -- no checks necessary
                return []
            # At this point, value is a date object.
            return self._check_if_value_fixed(value)
    

    Personally I would use a DateTimeField so you keep the timezone information, and just access .date when you need it, but you should be able to use datetime.date.today (assuming you don't want to use the auto_now_add option for some reason):

    import datetime
    
    class Submission(models.Model):
        date_created = models.DateField(
            default=datetime.date.today,
            blank=True,
        )