From 47829bacc7827fb7636f9b225bdb0b17bba005d0 Mon Sep 17 00:00:00 2001 From: William Mak Date: Thu, 20 Nov 2025 16:27:48 -0500 Subject: [PATCH] fix(issue-timeseries): Unfilled buckets when ts aren't aligned - When the start and end of the query wasn't aligned the page would error since the bucket check wouldn't match since ms were being included. This removes ms from the start/end during this check to resolve the issue --- .../organization_issue_timeseries.py | 4 ++ .../test_organization_issue_timeseries.py | 44 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/sentry/issues/endpoints/organization_issue_timeseries.py b/src/sentry/issues/endpoints/organization_issue_timeseries.py index d72522842b7472..db0f2c5603168e 100644 --- a/src/sentry/issues/endpoints/organization_issue_timeseries.py +++ b/src/sentry/issues/endpoints/organization_issue_timeseries.py @@ -290,6 +290,10 @@ def fill_timeseries( interval: timedelta, values: list[Row], ) -> list[Row]: + # remove microseconds + start = start.replace(microsecond=0) + end = end.replace(microsecond=0) + def iter_interval(start: datetime, end: datetime, interval: timedelta) -> Iterator[int]: while start <= end: yield int(start.timestamp() * 1000) diff --git a/tests/sentry/issues/endpoints/test_organization_issue_timeseries.py b/tests/sentry/issues/endpoints/test_organization_issue_timeseries.py index 6b9b38cc7cb4e7..1fe8a928a8ac3d 100644 --- a/tests/sentry/issues/endpoints/test_organization_issue_timeseries.py +++ b/tests/sentry/issues/endpoints/test_organization_issue_timeseries.py @@ -523,3 +523,47 @@ def test_other_with_resolved_issues(self) -> None: "valueUnit": None, "interval": 3_600_000, } + + def test_buckets_not_filling(self) -> None: + self.start = (self.end - timedelta(days=14)).replace(microsecond=1234) + + project = self.create_project() + self.create_group( + project=project, + status=1, + first_seen=self.start + timedelta(days=1), + resolved_at=self.start + timedelta(days=1, hours=1), + type=2, + ) + response = self.do_request( + { + "start": self.start, + "end": self.end, + "project": project.id, + "interval": "12h", + "category": "issue", + "yAxis": "count(new_issues)", + }, + ) + assert response.status_code == 200, response.content + assert response.data["meta"] == { + "dataset": "issue", + "start": self.start.timestamp() * 1000, + "end": self.end.timestamp() * 1000, + } + assert len(response.data["timeSeries"]) == 1 + timeseries = response.data["timeSeries"][0] + assert len(timeseries["values"]) == 29 + assert timeseries["values"] == [ + { + "incomplete": False, + "timestamp": round((self.start + timedelta(hours=x * 12)).timestamp() * 1000) - 1, + "value": 1 if x == 2 else 0, + } + for x in range(29) + ] + assert timeseries["meta"] == { + "valueType": "integer", + "valueUnit": None, + "interval": 43_200_000, + }