silentsokolov / django-admin-rangefilter

A Django app that lets you filter data by date range and numeric range in the admin UI
MIT License
713 stars 106 forks source link

How to fix timezones Issue ? #8

Closed a1Gupta closed 7 years ago

a1Gupta commented 7 years ago

Here is the case -

When using rangefilter, it filters based on UTC time zone, while time is shown as local time in admin. This creates inconsistency. This should be fixed and local time zone should be used for filtering.

silentsokolov commented 7 years ago

It is not possible to get the current time zone without passing it explicitly, read docs. I can modify the code so that you can set timezone, but implement middleware/session one myself.

a1Gupta commented 7 years ago

@silentsokolov I'm already doing middleware/session part using django-easy-timezones. This package detects user's timezone from IP and sets it in session. Can you do the later part to do filtering based on timezone when it's available in session ?

silentsokolov commented 7 years ago

Get new version django-admin-rangefilter, and override get_timezone

class DateTimeRangeFilterWithClientTZ(DateRangeFilter):
    def get_timezone(self, request):
        return request.session['timezone']
a1Gupta commented 7 years ago

@silentsokolov Thanks for adding this feature. This is the code I used to override get_timezone -

class DateTimeRangeFilterWithClientTZ(DateRangeFilter):
    def get_timezone(self, request):
        import pytz
        from django.utils import timezone
        client_tz = request.session.get('django_timezone')
        if client_tz:
            # convert string to timezone
            return pytz.timezone(client_tz)
        return timezone.get_default_timezone()
kylowrobelek commented 1 year ago

@silentsokolov that error occurs when Django > 4.0.0. Solution in rangefilter/filters.py:132: Change value = value.replace(tzinfo=tzname) to value = value.replace(tzinfo=zoneinfo.ZoneInfo(tzname.zone)) in make_dt_aware

Django docs: https://docs.djangoproject.com/en/4.2/topics/i18n/timezones/

silentsokolov commented 1 year ago

@kylowrobelek https://docs.djangoproject.com/en/4.2/ref/utils/#django.utils.timezone.get_default_timezone https://docs.python.org/3/library/zoneinfo.html#zoneinfo.ZoneInfo https://github.com/silentsokolov/django-admin-rangefilter/blob/master/rangefilter/filters.py#L119

Hmm ... I think everythink is ok

kylowrobelek commented 1 year ago

@silentsokolov It doesn't work when you trying to filter e.g. 2023-03-13 - 2023-03-13 in Europe/Stockholm zone and it returns records like 14-03-2023 12:01 a.m. - because creation time is 13-03-2023 22:01 p.m. UTC.

silentsokolov commented 1 year ago

@kylowrobelek Please, give more information. You override get_timezone? You set timezone in the django settings? Something else that can help testing it

kylowrobelek commented 1 year ago

@silentsokolov I'm using simple DateRangeFilter class. I tried to override get_timezone with simple return timezone.get_current_timezone() but it doesn't help. I have a TimezoneMiddleware (similar to @a1Gupta package) which activates Django timezone. Using USE_TZ = True and TIME_ZONE = 'UTC'.

silentsokolov commented 1 year ago

@kylowrobelek timezone.get_current_timezone() return local timezone (on machine) or TIME_ZONE by default, your TIME_ZONE = 'UTC'. Please, debug get_current_timezone() (print or somehow) and make sure that return needed timezone

kylowrobelek commented 1 year ago

Yes, it returns desired timezone but package does not care about it in Django 4.0.0

silentsokolov commented 1 year ago

@kylowrobelek If it returns a string, could you wrap this string to zoneinfo.ZoneInfo('string')? Or is returned object already ZoneInfo?

kylowrobelek commented 1 year ago

Ok, I've wrapped it with zoneinfo.ZoneInfo and used timezone.get_current_timezone() in override get_timezone (because original get_timezone returns UTC). Works fine :)

class DateTimeRangeFilterWithClientTZ(DateRangeFilter):
    def get_timezone(self, request):
        current_timezone = timezone.get_current_timezone()
        return zoneinfo.ZoneInfo(current_timezone.zone)