From 721ab9fbb931673a5f316ac02aa2f17aa10201ca Mon Sep 17 00:00:00 2001 From: Matias Bordese Date: Fri, 24 Feb 2023 17:54:20 -0300 Subject: [PATCH] Use UTC instead of Etc/UTC when passing tz to dateutil rrule (#1414) Fixes https://github.com/grafana/oncall-private/issues/1648 --- CHANGELOG.md | 1 + .../schedules/models/custom_on_call_shift.py | 3 ++ .../tests/test_custom_on_call_shift.py | 37 +++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 553cbb72..513d1b34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed importing of global grafana styles ([672](https://github.com/grafana/oncall/issues/672)) - Fixed UI permission related bug where Editors could not export their user iCal link +- Fixed error when a shift is created using Etc/UTC as timezone ### Changed diff --git a/engine/apps/schedules/models/custom_on_call_shift.py b/engine/apps/schedules/models/custom_on_call_shift.py index 5b6b1114..b823f800 100644 --- a/engine/apps/schedules/models/custom_on_call_shift.py +++ b/engine/apps/schedules/models/custom_on_call_shift.py @@ -588,6 +588,9 @@ class CustomOnCallShift(models.Model): def convert_dt_to_schedule_timezone(self, dt, time_zone): start_naive = dt.replace(tzinfo=None) + if time_zone and time_zone.lower() == "etc/utc": + # dateutil rrule breaks if Etc/UTC is given + time_zone = "UTC" return pytz.timezone(time_zone).localize(start_naive, is_dst=None) def get_rolling_users(self): diff --git a/engine/apps/schedules/tests/test_custom_on_call_shift.py b/engine/apps/schedules/tests/test_custom_on_call_shift.py index 47ff1d35..0eb3de07 100644 --- a/engine/apps/schedules/tests/test_custom_on_call_shift.py +++ b/engine/apps/schedules/tests/test_custom_on_call_shift.py @@ -1512,3 +1512,40 @@ def test_rolling_users_event_daily_by_day_start_none_convert_to_ical( ical_data = on_call_shift.convert_to_ical() # empty result since there is no event in the defined time range assert ical_data == "" + + +@pytest.mark.django_db +def test_etc_utc_timezone_convert_to_ical( + make_organization_and_user, + make_user_for_organization, + make_on_call_shift, +): + organization, user_1 = make_organization_and_user() + user_2 = make_user_for_organization(organization) + + date = timezone.now().replace(microsecond=0) + until = date + timezone.timedelta(days=30) + + data = { + "priority_level": 1, + "start": date, + "rotation_start": date, + "duration": timezone.timedelta(seconds=10800), + "frequency": CustomOnCallShift.FREQUENCY_HOURLY, + "interval": 2, + "until": until, + "time_zone": "Etc/UTC", + } + + on_call_shift = make_on_call_shift( + organization=organization, shift_type=CustomOnCallShift.TYPE_ROLLING_USERS_EVENT, **data + ) + rolling_users = [[user_1], [user_2]] + on_call_shift.add_rolling_users(rolling_users) + + ical_data = on_call_shift.convert_to_ical() + ical_rrule_until = on_call_shift.until.strftime("%Y%m%dT%H%M%S") + expected_rrule = f"RRULE:FREQ=HOURLY;UNTIL={ical_rrule_until}Z;INTERVAL=4;WKST=SU" + + assert on_call_shift.event_interval == len(rolling_users) * data["interval"] + assert expected_rrule in ical_data