What is the correct way to convert Django date and time fields to current timezone?

Question:

I feel like I’m missing something obvious:

I implemented timezones in my Django app using the SO solution here and it seems to be working (i.e. when the user changes to their timezone, Django’s {% get_current_timezone as TIME_ZONE %} and timezone.get_current_timezone.now() reflect that change)

However, I have a Django model with both a naive DateField and TimeField input. I have defined a property to return the formatted string with the date and time as follows:

# imports
from django.db import models
import pytz
from django.utils import timezone
from django.template.defaultfilters import date as format_date
from django.template.defaultfilters import time as format_time


class MyModel(models.Model):

    date = models.DateField(default=timezone.now, null=True, blank=True)
    time = models.TimeField(default=timezone.now, null=True, blank=True)
   ...

@property
    def datetime(self):
        date_str = format_date(self.date, "j N Y")
        time_str = format_time(self.time, 'g:i a') 

        return f"{date_str} at {time_str}"

How would I make the dates and times returned in the string changed to suit the timezone? (It can be assumed that they currently refer to UTC.) I’m currently trying with the time field. I tried both of these functions to make the time aware:

  • pytz.utc.localize(self.time)
  • self.time.replace(tzinfo=pytz.UTC)

But whenever I try to get the subsequent time for the zone through the statement:

local_time = self.time.replace(tzinfo=pytz.UTC)

I get the error:

‘datetime.time’ object has no attribute ‘astimezone’

Edit: I think the function that I should have been using was

local_time = aware_time.astimezone(timezone.get_current_timezone())

but the same error applies.

Asked By: Hermit

||

Answers:

If you want to manipulate time zones you need to be working with datetime objects. Create one with datetime.combine:

from datetime import datetime
from datetime.timezone import utc

dt = datetime.combine(self.date, self.time, utc)

At that point you have an aware datetime object and can convert it to another timezone, print it out, etc.