mirror of https://github.com/django/django.git
Fixed #33037 -- Fixed Trunc() with offset timezones on MySQL, SQLite, Oracle.
This commit is contained in:
parent
2aa8388110
commit
22285d366c
1
AUTHORS
1
AUTHORS
|
@ -919,6 +919,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Sergey Fedoseev <fedoseev.sergey@gmail.com>
|
Sergey Fedoseev <fedoseev.sergey@gmail.com>
|
||||||
Sergey Kolosov <m17.admin@gmail.com>
|
Sergey Kolosov <m17.admin@gmail.com>
|
||||||
Seth Hill <sethrh@gmail.com>
|
Seth Hill <sethrh@gmail.com>
|
||||||
|
Shafiya Adzhani <adz.arsym@gmail.com>
|
||||||
Shai Berger <shai@platonix.com>
|
Shai Berger <shai@platonix.com>
|
||||||
Shannon -jj Behrens <https://www.jjinux.com/>
|
Shannon -jj Behrens <https://www.jjinux.com/>
|
||||||
Shawn Milochik <shawn@milochik.com>
|
Shawn Milochik <shawn@milochik.com>
|
||||||
|
|
|
@ -118,7 +118,10 @@ def _sqlite_datetime_parse(dt, tzname=None, conn_tzname=None):
|
||||||
hours, minutes = offset.split(":")
|
hours, minutes = offset.split(":")
|
||||||
offset_delta = timedelta(hours=int(hours), minutes=int(minutes))
|
offset_delta = timedelta(hours=int(hours), minutes=int(minutes))
|
||||||
dt += offset_delta if sign == "+" else -offset_delta
|
dt += offset_delta if sign == "+" else -offset_delta
|
||||||
dt = timezone.localtime(dt, zoneinfo.ZoneInfo(tzname))
|
# The tzname may originally be just the offset e.g. "+3:00",
|
||||||
|
# which becomes an empty string after splitting the sign and offset.
|
||||||
|
# In this case, use the conn_tzname as fallback.
|
||||||
|
dt = timezone.localtime(dt, zoneinfo.ZoneInfo(tzname or conn_tzname))
|
||||||
return dt
|
return dt
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -200,6 +200,8 @@ def split_tzname_delta(tzname):
|
||||||
if sign in tzname:
|
if sign in tzname:
|
||||||
name, offset = tzname.rsplit(sign, 1)
|
name, offset = tzname.rsplit(sign, 1)
|
||||||
if offset and parse_time(offset):
|
if offset and parse_time(offset):
|
||||||
|
if ":" not in offset:
|
||||||
|
offset = f"{offset}:00"
|
||||||
return name, sign, offset
|
return name, sign, offset
|
||||||
return tzname, None, None
|
return tzname, None, None
|
||||||
|
|
||||||
|
|
|
@ -1832,17 +1832,18 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
|
||||||
end_datetime = timezone.make_aware(end_datetime)
|
end_datetime = timezone.make_aware(end_datetime)
|
||||||
self.create_model(start_datetime, end_datetime)
|
self.create_model(start_datetime, end_datetime)
|
||||||
self.create_model(end_datetime, start_datetime)
|
self.create_model(end_datetime, start_datetime)
|
||||||
melb = zoneinfo.ZoneInfo("Australia/Melbourne")
|
|
||||||
|
|
||||||
def assertDatetimeKind(kind):
|
def assertDatetimeKind(kind, tzinfo):
|
||||||
truncated_start = truncate_to(start_datetime.astimezone(melb), kind, melb)
|
truncated_start = truncate_to(
|
||||||
truncated_end = truncate_to(end_datetime.astimezone(melb), kind, melb)
|
start_datetime.astimezone(tzinfo), kind, tzinfo
|
||||||
|
)
|
||||||
|
truncated_end = truncate_to(end_datetime.astimezone(tzinfo), kind, tzinfo)
|
||||||
queryset = DTModel.objects.annotate(
|
queryset = DTModel.objects.annotate(
|
||||||
truncated=Trunc(
|
truncated=Trunc(
|
||||||
"start_datetime",
|
"start_datetime",
|
||||||
kind,
|
kind,
|
||||||
output_field=DateTimeField(),
|
output_field=DateTimeField(),
|
||||||
tzinfo=melb,
|
tzinfo=tzinfo,
|
||||||
)
|
)
|
||||||
).order_by("start_datetime")
|
).order_by("start_datetime")
|
||||||
self.assertSequenceEqual(
|
self.assertSequenceEqual(
|
||||||
|
@ -1853,15 +1854,17 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
def assertDatetimeToDateKind(kind):
|
def assertDatetimeToDateKind(kind, tzinfo):
|
||||||
truncated_start = truncate_to(start_datetime.astimezone(melb).date(), kind)
|
truncated_start = truncate_to(
|
||||||
truncated_end = truncate_to(end_datetime.astimezone(melb).date(), kind)
|
start_datetime.astimezone(tzinfo).date(), kind
|
||||||
|
)
|
||||||
|
truncated_end = truncate_to(end_datetime.astimezone(tzinfo).date(), kind)
|
||||||
queryset = DTModel.objects.annotate(
|
queryset = DTModel.objects.annotate(
|
||||||
truncated=Trunc(
|
truncated=Trunc(
|
||||||
"start_datetime",
|
"start_datetime",
|
||||||
kind,
|
kind,
|
||||||
output_field=DateField(),
|
output_field=DateField(),
|
||||||
tzinfo=melb,
|
tzinfo=tzinfo,
|
||||||
),
|
),
|
||||||
).order_by("start_datetime")
|
).order_by("start_datetime")
|
||||||
self.assertSequenceEqual(
|
self.assertSequenceEqual(
|
||||||
|
@ -1872,15 +1875,17 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
def assertDatetimeToTimeKind(kind):
|
def assertDatetimeToTimeKind(kind, tzinfo):
|
||||||
truncated_start = truncate_to(start_datetime.astimezone(melb).time(), kind)
|
truncated_start = truncate_to(
|
||||||
truncated_end = truncate_to(end_datetime.astimezone(melb).time(), kind)
|
start_datetime.astimezone(tzinfo).time(), kind
|
||||||
|
)
|
||||||
|
truncated_end = truncate_to(end_datetime.astimezone(tzinfo).time(), kind)
|
||||||
queryset = DTModel.objects.annotate(
|
queryset = DTModel.objects.annotate(
|
||||||
truncated=Trunc(
|
truncated=Trunc(
|
||||||
"start_datetime",
|
"start_datetime",
|
||||||
kind,
|
kind,
|
||||||
output_field=TimeField(),
|
output_field=TimeField(),
|
||||||
tzinfo=melb,
|
tzinfo=tzinfo,
|
||||||
)
|
)
|
||||||
).order_by("start_datetime")
|
).order_by("start_datetime")
|
||||||
self.assertSequenceEqual(
|
self.assertSequenceEqual(
|
||||||
|
@ -1891,6 +1896,10 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
timezones = [
|
||||||
|
zoneinfo.ZoneInfo("Australia/Melbourne"),
|
||||||
|
zoneinfo.ZoneInfo("Etc/GMT+10"),
|
||||||
|
]
|
||||||
date_truncations = ["year", "quarter", "month", "week", "day"]
|
date_truncations = ["year", "quarter", "month", "week", "day"]
|
||||||
time_truncations = ["hour", "minute", "second"]
|
time_truncations = ["hour", "minute", "second"]
|
||||||
tests = [
|
tests = [
|
||||||
|
@ -1900,8 +1909,13 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
|
||||||
]
|
]
|
||||||
for assertion, truncations in tests:
|
for assertion, truncations in tests:
|
||||||
for truncation in truncations:
|
for truncation in truncations:
|
||||||
with self.subTest(assertion=assertion.__name__, truncation=truncation):
|
for tzinfo in timezones:
|
||||||
assertion(truncation)
|
with self.subTest(
|
||||||
|
assertion=assertion.__name__,
|
||||||
|
truncation=truncation,
|
||||||
|
tzinfo=tzinfo.key,
|
||||||
|
):
|
||||||
|
assertion(truncation, tzinfo)
|
||||||
|
|
||||||
qs = DTModel.objects.filter(
|
qs = DTModel.objects.filter(
|
||||||
start_datetime__date=Trunc(
|
start_datetime__date=Trunc(
|
||||||
|
|
Loading…
Reference in New Issue