Flevo CFD

Handle Timezones in Django Rest Framework

What is Timezone?

A timezone is a designate area on the globe that has the same standard time. Timezones are usually defined by the number of hours that they are offset from Coordinated Universal Time (UTC).

For example “22:10:00 UTC+2” means that the time is 22:10:00 in the timezone that is 2 hours ahead of UTC.

GMT stands for Greenwich Mean Time. It is the time at the Royal Observatory in Greenwich, London. GMT is the same as UTC.

Why do we bother with timezones? Can’t we just use UTC everywhere?

The main purpose of timezones is to allow people to coordinate activities across different regions and to avoid confusion when scheduling events.

While it’s true that using UTC everywhere would simplify things, it’s not always practical.

For example, we expect the sun to rise in the morning and set in the evening no matter where we are in the world. If we all used UTC, the sun would rise at different times in different parts of the world, which would be confusing.

I’ve recently learned that China has only one timezone due to political reasons. The whole country uses the same timezone, even though it spans five geographical time zones. it brought a lot of confusion to the people living in country.

How to enable timezone support in Django Rest Framework?

First, you need to set the USE_TZ setting to True in your Django settings.

1
USE_TZ = True

This setting tells Django to use timezone-aware datetimes. When USE_TZ is set to True, Django stores datetimes in the database in UTC and converts them to the user’s timezone (The timezone needs to be activated first).

A naive datetime is a datetime that doesn’t have a timezone.

1
2
3
4
5
6
7
8
9
import zoneinfo
from datetime import datetime


naive_datetime = datetime(2024, 5, 22, 17, 59, 46)
timezone_aware_datetime = datetime(
    2024, 5, 22, 17, 59, 46,
    tzinfo=zoneinfo.ZoneInfo('Europe/Paris')
)

Even if you don’t need to support different timezones, it’s a good practice to set USE_TZ to True to avoid timezone-related bugs and also support daylight saving time.

What is daylight saving time? Daylight saving time is the practice of setting the clocks forward by one hour during the warmer months of the year to extend the evening daylight. to save energy and make better use of daylight.

First, we need to add new field to the user model to store the user’s timezone.

Next, we need to figure the user’s timezone and activate it. in Django you would create a middleware to do this. However DRF has its own authentication system, so in a Django middleware we can’t determine if the user is authenticated or not.

Instead, we can use a mixin to set the timezone for the request. Here’s an example of how you can do this

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import zoneinfo


class ActivateTimezoneMixin:
    def initial(self, request, *args, **kwargs):
        super().initial(request, *args, **kwargs)

        tzname = request.user.time_zone if request.user.is_authenticated else None
        if tzname:
            timezone.activate(zoneinfo.ZoneInfo(tzname))
        else:
            timezone.deactivate()

You can then use this mixin in your views to activate the timezone for authenticated users.

1
2
class MyView(ActivateTimezoneMixin, APIView):
    ...