Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions mssql/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,21 @@ def max_in_list_size(self):

def _convert_field_to_tz(self, field_name, tzname):
if tzname and settings.USE_TZ and self.connection.timezone_name != tzname:
offset = self._get_utcoffset(tzname)
offset = self._get_timezone_offset(tzname)
field_name = 'DATEADD(second, %d, %s)' % (offset, field_name)
return field_name

def _convert_sql_to_tz(self, sql, params, tzname):
if tzname and settings.USE_TZ and self.connection.timezone_name != tzname:
offset = self._get_utcoffset(tzname)
offset = self._get_timezone_offset(tzname)
sql = 'DATEADD(second, %d, %s)' % (offset, sql)
return sql, params

def _get_timezone_offset(self, tzname):
connection_tzname = self.connection.timezone_name
connection_offset = self._get_utcoffset(connection_tzname) if connection_tzname else 0
return self._get_utcoffset(tzname) - connection_offset
Comment on lines +46 to +47

def _get_utcoffset(self, tzname):
"""
Returns UTC offset for given time zone in seconds
Expand Down Expand Up @@ -614,10 +619,7 @@ def adapt_datetimefield_value(self, value):

if timezone.is_aware(value):
if settings.USE_TZ:
# When support for time zones is enabled, Django stores datetime information
# in UTC in the database and uses time-zone-aware objects internally
# source: https://docs.djangoproject.com/en/dev/topics/i18n/timezones/#overview
value = value.astimezone(datetime.timezone.utc)
value = timezone.make_naive(value, self.connection.timezone)
else:
# When USE_TZ is False, settings.TIME_ZONE is the time zone in
# which Django will store all datetimes
Expand Down
75 changes: 74 additions & 1 deletion testapp/tests/test_timezones.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,85 @@
# Licensed under the BSD license.

import datetime
from types import SimpleNamespace

from django.db import connection
from django.test import TestCase
from django.test import SimpleTestCase, TestCase
from django.test.utils import override_settings

from mssql.operations import DatabaseOperations

from ..models import TimeZone


class TestDatabaseOperations(SimpleTestCase):
@override_settings(USE_TZ=True)
def test_adapt_datetimefield_value_uses_database_timezone(self):
database_timezone = datetime.timezone(datetime.timedelta(hours=3))
operations = DatabaseOperations(
SimpleNamespace(
timezone=database_timezone,
timezone_name="Africa/Nairobi",
)
)
value = datetime.datetime(2026, 1, 15, 12, tzinfo=datetime.timezone.utc)

adapted = operations.adapt_datetimefield_value(value)

self.assertEqual(adapted, datetime.datetime(2026, 1, 15, 15))

@override_settings(USE_TZ=True)
def test_datetime_sql_conversion_uses_database_timezone(self):
operations = DatabaseOperations(SimpleNamespace(timezone_name="Asia/Bangkok"))
expected_sql = "DATEADD(second, -14400, column)"

self.assertEqual(
operations._convert_field_to_tz("column", "Africa/Nairobi"),
expected_sql,
)
self.assertEqual(
operations._convert_sql_to_tz(
"column",
("parameter",),
"Africa/Nairobi",
),
(expected_sql, ("parameter",)),
)

@override_settings(USE_TZ=True)
def test_datetime_sql_conversion_from_utc(self):
expected_sql = "DATEADD(second, 10800, column)"

for timezone_name in (None, "UTC"):
with self.subTest(timezone_name=timezone_name):
operations = DatabaseOperations(
SimpleNamespace(timezone_name=timezone_name)
)
self.assertEqual(
operations._convert_field_to_tz("column", "Africa/Nairobi"),
expected_sql,
)

@override_settings(USE_TZ=True)
def test_datetime_sql_conversion_skips_matching_timezone(self):
operations = DatabaseOperations(
SimpleNamespace(timezone_name="Africa/Nairobi")
)

self.assertEqual(
operations._convert_field_to_tz("column", "Africa/Nairobi"),
"column",
)
self.assertEqual(
operations._convert_sql_to_tz(
"column",
("parameter",),
"Africa/Nairobi",
),
("column", ("parameter",)),
)


class TestDateTimeField(TestCase):

def test_iso_week_day(self):
Expand Down
Loading