-
-
Notifications
You must be signed in to change notification settings - Fork 7k
Fix DateTimeField TZ handling #5435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- tests "current" timezone activation - tests output for non-UTC timezones
@@ -44,7 +44,11 @@ You can determine your currently installed version using `pip freeze`: | |||
|
|||
* Fix `DjangoModelPermissions` to ensure user authentication before calling the view's `get_queryset()` method. As a side effect, this changes the order of the HTTP method permissions and authentication checks, and 405 responses will only be returned when authenticated. If you want to replicate the old behavior, see the PR for details. [#5376][gh5376] | |||
* Deprecated `exclude_from_schema` on `APIView` and `api_view` decorator. Set `schema = None` or `@schema(None)` as appropriate. [#5422][gh5422] | |||
* Timezone-aware `DateTimeField`s now respect active or default) `timezone` during serialization, instead of always using UTC. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like an erroneous ")" here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last DRF update changed how timestamps are returned from the endpoints. Previously they were formatted as 2017-12-11T13:01:23Z and now they are formatted as 2017-12-11T15:01:23+02:00 I.e. they use the timezone configured in the settings rather than UTC. See encode/django-rest-framework#5435 for more info.
This added new "inconsistencies" as well and I don't think there's really a better way to handle any of this and the client should always be able to handle timezones. But the change that converts parsed datetime to the default timezone adds the following inconsistency:
At least previously, sending the server a date would always return the same date in the the timezone it was sent, now the interaction between a client side library like momentjs and DRF gets really ugly since datetimes are always sent in one timezone and received in another, when previously at least that would be kept consistent. This is not a complaint or anything since client side should be able to handle this just fine, but just a warning about inconsistencies are still here and the previous behavior might have been the right one. Another inconsistency would be mixing the renderer class and serializer, renderer will always use w/e timezone the date is (most of the time UTC if it was loaded by django) while the serializer will now always use a different timezone (unless UTC is the default one) so you might end up with two API endpoints that returns dates in different formats. I think the serializer shouldn't mess around with the timezone at all, unless the given date had no timezone and timezone is enabled in which case it needs to be set, and any display logic should be purely client side, since this is a REST API after all. |
Hey @cristianocca. I think you're right that there's no perfect way to handle this. IMO Setting the default timezone to UTC, and using UTC everywhere, is normally going to be your best option (if what you want is least surprises). |
This has caused us issues after upgrading, especially since I think the release notes don't actually cover what the real behaviour was prior to the change. Previously, we were able to provide a datetime like I plan to subclass DateTimeField to make the |
Hi @alexcreid - this sounds like it might be a bug, given that non-UTC timezones are supported. Would you mind opening a report so we don't lose track of this? |
Hi @alexcreid. Before this fix on create/update you would get back the same timezone you submitted with but on a later retrieve it would come back as UTC. This inconsistency was the body of #3732. Now the serialisation respects current or active timezone. So, question, how's your DB storing the datetimes? Are the entries not normalised to a single timezone? If they are then, even with the old behaviour, there's no way of maintaining the extra timezone info. Either way, as @rpkilby says, can you open a new ticket explaining your issue in full and we'll have a look. Ta. |
Hey, I just encountered this issue my self. I had a serializer field defined like this:
I expected the field to be rendered in local time (especially since I explicitly stated the desired timezone). To my surprise it was rendered in UTC (the database timezone). Is there a reason the date is only made aware in |
@hakib Can you try adding a test to |
I think that a better fix (rather than changing the previous behavior) would have been fixing the browsable API to correctly parse and render datetimes on the client-side or server side configured timezone. Right now you are even losing information when doing all those timezone changes to the datetime object, not like it really matters but if for some reason you want to know the original timezone a parsed date came in, you will need to add a new field or overwrite the serializer. |
@cristianocca The issue here wasn't with the Browsable API, in except that it uses serializers, but rather the inconsistency of representation between different HTTP methods (create/update vs retrieve). We've gone with what we hope is a sensible solution for most users. (#5821 looks like a bug not respecting the active timezone, so we'll look at that.) If you do want to maintain the submitted timezone info, subclassing Potentially we could look at a PR making this user-configurable. My worry would be introducing a complex change where the simple subclass is readily available. (We'd have to see the actual PR to say.) |
Actually that wont work. The subclass would have to override |
@carltongibson wrote:
When we store datetimes, they're invariably UTC. Our application needs to deal with datetimes that are in multiple timezones which are in neither the client's nor the server's timezone, so this doesn't map neatly to the Django way of having a single 'active' timezone. Since we had logic to ensure that these datetimes always had the correct tzinfo attached, these would be serialised by the DRF as ISO 8601 strings with the correct offset from UTC at the end before this change. I'll open an issue with some more details when I get a chance. It might be that this is too niche to merit any code changes, but if so, it'd be nice to have the fact that datetimes will be output in the active Django timezone documented, since I think that counts as surprising behaviour. |
* Add failing test for to_representation with explicit default timezone See discussion here: #5435 (comment) * Always run enforce_timezone
* Add failing test for to_representation with explicit default timezone See discussion here: encode#5435 (comment) * Always run enforce_timezone
Adds Release note, rebases and closes #5408. Closes #3732