Add a setting to set a default timezone for datetime representations

DRF, by default, uses Django's timezone settings for deciding on how to represent datetimes if timezone support is active.
This setting allows the user to instead point to a different timezone for their API endpoint in particular.
This commit is contained in:
Raphael Gaschignard 2018-04-05 15:14:52 +09:00
parent 6602171184
commit 055f35406a
4 changed files with 53 additions and 1 deletions

View File

@ -306,6 +306,14 @@ May be a list including the string `'iso-8601'` or Python [strftime format][strf
Default: `['iso-8601']` Default: `['iso-8601']`
#### DATETIME_TZ
If set, used as the canonical timezone for `DateTimeField` serialization. If this is not set but Django timezone support is active, Django's timezone is instead used
May be any of `None`, or a `datetime.tzinfo` object (such as `pytz.timezone('Asia/Kolkata')`)
Default: None
#### DATE_FORMAT #### DATE_FORMAT
A format string that should be used by default for rendering the output of `DateField` serializer fields. If `None`, then `DateField` serializer fields will return Python `date` objects, and the date encoding will be determined by the renderer. A format string that should be used by default for rendering the output of `DateField` serializer fields. If `None`, then `DateField` serializer fields will return Python `date` objects, and the date encoding will be determined by the renderer.

View File

@ -1174,7 +1174,13 @@ class DateTimeField(Field):
return value return value
def default_timezone(self): def default_timezone(self):
return timezone.get_current_timezone() if settings.USE_TZ else None if settings.USE_TZ:
if api_settings.DATETIME_TZ:
return api_settings.DATETIME_TZ
else:
return timezone.get_current_timezone()
else:
return None
def to_internal_value(self, value): def to_internal_value(self, value):
input_formats = getattr(self, 'input_formats', api_settings.DATETIME_INPUT_FORMATS) input_formats = getattr(self, 'input_formats', api_settings.DATETIME_INPUT_FORMATS)

View File

@ -107,6 +107,7 @@ DEFAULTS = {
'DATETIME_FORMAT': ISO_8601, 'DATETIME_FORMAT': ISO_8601,
'DATETIME_INPUT_FORMATS': (ISO_8601,), 'DATETIME_INPUT_FORMATS': (ISO_8601,),
'DATETIME_TZ': None,
'TIME_FORMAT': ISO_8601, 'TIME_FORMAT': ISO_8601,
'TIME_INPUT_FORMATS': (ISO_8601,), 'TIME_INPUT_FORMATS': (ISO_8601,),

View File

@ -14,6 +14,7 @@ from django.utils.timezone import activate, deactivate, utc
import rest_framework import rest_framework
from rest_framework import compat, serializers from rest_framework import compat, serializers
from rest_framework.fields import DjangoImageField, is_simple_callable from rest_framework.fields import DjangoImageField, is_simple_callable
from rest_framework.settings import api_settings
try: try:
import pytz import pytz
@ -1273,6 +1274,42 @@ class TestTZWithDateTimeField(FieldValues):
cls.field = serializers.DateTimeField(default_timezone=kolkata) cls.field = serializers.DateTimeField(default_timezone=kolkata)
@pytest.mark.skipif(pytz is None, reason='pytz not installed')
@override_settings(TIME_ZONE='Asia/Kolkata', USE_TZ=True)
class TestDateTimeWithOverrideField(FieldValues, TestCase):
"""
Valid and invalid values for `DateTimeField` when not using UTC as the timezone.
"""
@classmethod
def setup_class(cls):
# use class setup method, as class-level attribute will still be evaluated even if test is skipped
kolkata = pytz.timezone('Asia/Kolkata')
paris = pytz.timezone('Europe/Paris')
# set the timezone to a specific timezone that isn't the django-level setting
cls.old_setting = api_settings.DATETIME_TZ
api_settings.DATETIME_TZ = paris
cls.valid_inputs = {
'2016-12-19T10:00:00': paris.localize(datetime.datetime(2016, 12, 19, 10)),
# datetimes are reworked into the paris tz
'2016-12-19T10:00:00+05:30': paris.localize(datetime.datetime(2016, 12, 19, 5, 30)),
# naive datetimes are assumed to be in the paris tz
datetime.datetime(2016, 12, 19, 10): paris.localize(datetime.datetime(2016, 12, 19, 10)),
}
cls.invalid_inputs = {}
cls.outputs = {
datetime.datetime(2016, 12, 19, 10): '2016-12-19T10:00:00+01:00',
datetime.datetime(2016, 12, 19, 4, 30, tzinfo=utc): '2016-12-19T05:30:00+01:00',
}
cls.field = serializers.DateTimeField()
@classmethod
def teardown_class(cls):
api_settings.DATETIME_TZ = cls.old_setting
@pytest.mark.skipif(pytz is None, reason='pytz not installed') @pytest.mark.skipif(pytz is None, reason='pytz not installed')
@override_settings(TIME_ZONE='UTC', USE_TZ=True) @override_settings(TIME_ZONE='UTC', USE_TZ=True)
class TestDefaultTZDateTimeField(TestCase): class TestDefaultTZDateTimeField(TestCase):