diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 3ca7d682e..45fadc9f9 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -903,7 +903,12 @@ class DateTimeField(Field): When `self.default_timezone` is not `None`, always return aware datetimes. """ if (self.default_timezone is not None) and not timezone.is_aware(value): - return timezone.make_aware(value, self.default_timezone) + # If a timezone is active we want to use it, but if not we want to use the timezone + # specified for this field over the system's default timezone. + if hasattr(timezone._active, 'value'): + return timezone.make_aware(value, timezone._active.value) + else: + return timezone.make_aware(value, self.default_timezone) elif (self.default_timezone is None) and timezone.is_aware(value): return timezone.make_naive(value, timezone.UTC()) return value @@ -936,6 +941,11 @@ class DateTimeField(Field): self.fail('invalid', format=humanized_format) def to_representation(self, value): + if timezone.is_aware(value): + # convert the datetime to the timezone the user is expecting + tz = getattr(timezone._active, "value", self.default_timezone) + value = timezone.localtime(value, tz) + if self.format is None: return value diff --git a/tests/test_fields.py b/tests/test_fields.py index 76e6d9d60..80375789c 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -4,6 +4,7 @@ from decimal import Decimal import django import pytest +from django.test.utils import override_settings from django.utils import timezone import rest_framework @@ -848,6 +849,40 @@ class TestNoOutputFormatDateField(FieldValues): field = serializers.DateField(format=None) +class FakeTimezone(datetime.tzinfo): + + def __repr__(self): + return "" + + def utcoffset(self, dt): + return datetime.timedelta(1) + + def tzname(self, dt): + return "FakeTimezone" + + def dst(self, dt): + return datetime.timedelta(1) + + +class TestAwareDateTimeField: + + @override_settings(USE_TZ=True) + def test_with_timezone_active(self): + naive_now = timezone.make_naive(timezone.now(), timezone.UTC()) + timezone.activate(FakeTimezone()) + field = serializers.DateTimeField(default_timezone=timezone.UTC()) + aware_now = field.enforce_timezone(naive_now) + assert aware_now.tzname() == 'FakeTimezone' + timezone.deactivate() + + @override_settings(USE_TZ=True) + def test_without_timezone_active(self): + naive_now = timezone.make_naive(timezone.now(), timezone.UTC()) + field = serializers.DateTimeField(default_timezone=timezone.UTC()) + aware_now = field.enforce_timezone(naive_now) + assert aware_now.tzname() == 'UTC' + + class TestDateTimeField(FieldValues): """ Valid and invalid values for `DateTimeField`.