Skip to content

timeinterval: fix negative days_of_month across DST transitions - #5447

Open
sueun-dev wants to merge 1 commit into
prometheus:mainfrom
sueun-dev:fix-daysinmonth-dst
Open

timeinterval: fix negative days_of_month across DST transitions#5447
sueun-dev wants to merge 1 commit into
prometheus:mainfrom
sueun-dev:fix-daysinmonth-dst

Conversation

@sueun-dev

Copy link
Copy Markdown

daysInMonth computes a month's length by dividing the elapsed duration between the first of the month and the first of the next month by 24 hours. When a location is set and that month contains a spring-forward DST transition, the span is 743 wall-clock hours rather than 744, so the truncating division returns 30 for a 31-day month.

ContainsTime uses that count to resolve negative days_of_month entries such as -1 (the last day of the month). So a "last day of the month" mute with a non-UTC location resolves to the 30th during a spring-forward month: it does not fire on the actual last day (the 31st) and fires a day early on the 30th.

Reproduced with days_of_month: ['-1'] and location: America/New_York for March 2021 (spring-forward on the 14th): before the change ContainsTime(Mar 31) is false and ContainsTime(Mar 30) is true; after, it is the reverse. A non-DST month (May) is unaffected either way.

The fix computes the count with calendar arithmetic — day 0 of the following month is the last day of the current month — which does not depend on DST. I added a regression case to timeIntervalTestCases covering -1 in America/New_York across the March transition; it fails before and passes after.

Tested with go test ./timeinterval/... plus the dependent notify, config, and dispatch packages.

[BUGFIX] Time intervals: fix negative `days_of_month` indices resolving one day early in a `location` whose month contains a spring-forward DST transition.

…ions

daysInMonth derived the month length by dividing the elapsed duration
between the first of the month and the first of the next month by 24
hours. In a location whose month contains a spring-forward daylight
saving transition that span is 743 wall-clock hours, not 744, so the
truncating division returns 30 for a 31-day month.

ContainsTime feeds that count into negative days_of_month resolution
(for example -1 for the last day of the month), so with a non-UTC
location set, a "last day" mute resolves to the 30th during a
spring-forward month: it fails to fire on the true last day (31st) and
fires a day early on the 30th.

Compute the count with calendar arithmetic instead: day 0 of the
following month normalizes to the last day of the current month, which
is DST-independent. Add a regression case covering -1 in
America/New_York across the March spring-forward transition.

Signed-off-by: Sueun Cho <sueun.dev@gmail.com>
@sueun-dev
sueun-dev requested a review from a team as a code owner August 13, 2026 09:44
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f59dbc04-f07d-4063-b132-2d07bc9fa9dd

📥 Commits

Reviewing files that changed from the base of the PR and between 55d0d79 and bd6e84e.

📒 Files selected for processing (2)
  • timeinterval/timeinterval.go
  • timeinterval/timeinterval_test.go

📝 Walkthrough

Walkthrough

daysInMonth now uses calendar normalization instead of duration arithmetic. A regression test verifies that a negative day-of-month interval includes March 31 and excludes March 30 across the America/New_York daylight-saving transition.

Changes

Calendar Month Length

Layer / File(s) Summary
Calendar month calculation and regression coverage
timeinterval/timeinterval.go, timeinterval/timeinterval_test.go
daysInMonth calculates month length from the next month's day zero. Tests verify correct last-day interval behavior during the March 2021 daylight-saving transition.

Estimated code review effort: 2 (Simple) | ~10 minutes

Mergeability Score: ⚪ Minimal · up to bd6e8

This change corrects negative month-day resolution across spring-forward DST transitions and adds regression coverage; no actionable merge-blocking risk remains after normal checks and review.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the DST-related fix for negative days_of_month resolution.
Description check ✅ Passed The description explains the bug, fix, regression test, affected behavior, test commands, and release note.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants