Fix timezone shifts in news/posters/etc. (every forms.DateTimeField)
The broken behaviour that was previously observed and that this MR tries to fix:
- Create a news at
/com/news/createwith start date
2020-04-17 20:00:00and end date
/com/news/adminit gets displayed correctly.
- However, if you edit it at
2020-04-17 20:00:00as start and end dates (assuming the current timezone is UTC+2).
- If you submit which touching anything, the event/news/poster/other gets shifted by 2h (because it's summer time, only 1h if it's winter).
Timezone issue! What I understood from a (loooooong) debugging session (and django's doc) is that the database stores the datetime as UTC (
2020-04-17 18:00:00 in our case). When it is displayed in a template, we use the
localtime filter to adjust to the current timezone. However, a
forms.DateTimeField is passed the datetime to display as a string. It was initially displayed as is (coming from the database) and therefore the UTC value was displayed. To solve this, the value which comes from the database must be parsed into a datetime to adjust the timezone.
It is done in three steps in the
prepare_value(self, value) method which is used to prepare the database value to be displayed in the form (this MR changes nothing for the form validation and database insertion steps):
django.utils.dateparse.parse_datetime(string_dt), which returns a naive datetime storing the UTC time.
django.utils.timezone.make_aware(naive_dt, timezone.utc)which turns the naive datetime into an aware datetime which is "located" in UTC.
django.forms.utils.to_current_timezone(aware_dt)which turns an aware datetime into a naive datetime with the datetime which corresponds in the current timezone.
>>> from django.utils.dateparse import parse_datetime >>> from django.utils import timezone >>> from django.forms.utils import to_current_timezone >>> parse_datetime("2020-04-17 18:00:00") datetime.datetime(2020, 4, 17, 18, 0) >>> timezone.make_aware(_, timezone.utc) datetime.datetime(2020, 4, 17, 18, 0, tzinfo=<UTC>) >>> to_current_timezone(_) datetime.datetime(2020, 4, 17, 20, 0)
It is then turned back into a string to be displayed. It's important because otherwise it is automatically converted using the locale and on my PC it becomes
17/04/2020 20:00:00 (I'd say it's django's settings and not GNU/Linux's locale setting because mine is
en_US.UTF-8) and the front-end doesn't support this format (the backend neither btw).
It's a WIP because I would like to have opinions on the approach and it needs to be tested by other people! An exhaustive list of pages this MR concerns:
/club/:id/sellings: the sellings page of a club (id=1 for the AE club).
/com/news/create: the news creation page.
/com/news/:id/edit: the news edit page (create on on
/com/news/createthen test editing it).
/counter/admin/cash_summary/list: by default there is nothing in local (but there is something on the prod). I don't know what needs to be done to have something in local.
/election/add: the election creation page.
/election/:id/edit: the election edit page (id=1 is populated).
/subscription/stats: the subscription statistics page.
/subscription: the subscription creation page.
I await (async hehe) your reviews. :)