Skip to content

Conversation

@adityathebe
Copy link
Member

@adityathebe adityathebe commented Jan 5, 2026

Example:

time_interval.business_hours=[{"weekdays":["monday:friday"],"times":[{"start_time":"09:00","end_time":"17:00"}],"location":"Asia/Kathmandu"}]

used this time format: https://prometheus.io/docs/alerting/latest/configuration/#time_interval

Example:

times:
- start_time: 09:00
  end_time: 17:00
weekdays: ['monday:friday']

Accept from properties for now and then we can move to CRD or tenant wide UI settings

Summary by CodeRabbit

  • New Features
    • Add support for defining and retrieving JSON/YAML time-interval configurations and a dedicated business-hours key with sensible default hours when unset.
    • Allow aggregation of multiple named interval sets and evaluation of whether a given date/time falls within configured intervals (time-of-day, weekdays, days-of-month, months, years, and timezone-aware handling).
    • Provide serialization/deserialization and user-friendly textual formats for interval definitions.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 5, 2026

Walkthrough

Adds a new time-interval engine package for parsing/evaluating complex time intervals and extends the properties package with accessors to read JSON-encoded time-interval values (default key business_hours) and return aggregated TimeIntervals.

Changes

Cohort / File(s) Summary
Properties API Extension
properties/properties.go
Adds BusinessHours() (timeinterval.TimeIntervals, error), TimeIntervals(keys ...string) (timeinterval.TimeIntervals, error), and (*Properties) TimeIntervals(keys ...string) (timeinterval.TimeIntervals, error). Reads time_interval.<key> JSON values, aggregates parsed TimeIntervals, provides default business_hours (Mon–Fri 09:00–17:00) when unset, and wraps JSON errors with property context.
Time-interval engine (new)
timeinterval/timeinterval.go
New package implementing time-interval types and logic: Intervener, TimeInterval, TimeIntervals, TimeRange, WeekdayRange, DayOfMonthRange, MonthRange, YearRange, Location, and helpers. Adds (un)marshalling (YAML/JSON/Text), validation, parsing (e.g., 09:00-17:00, monday:friday), ContainsTime, NewIntervener, and (Intervener) Mutes.

Sequence Diagram(s)

mermaid
sequenceDiagram
actor Caller
participant Properties as properties package
participant Store as properties storage
participant TI as timeinterval package

Caller->>Properties: BusinessHours() / TimeIntervals(keys...)
Properties->>Store: lookup `time_interval.<key>` (or absent)
alt property found
    Store-->>Properties: JSON string
    Properties->>TI: json.Unmarshal -> TimeIntervals
    TI-->>Properties: parsed TimeIntervals
    Properties-->>Caller: aggregated TimeIntervals
else property missing
    Properties-->>TI: return default TimeIntervals (business_hours)
    TI-->>Properties: default TimeIntervals
    Properties-->>Caller: aggregated TimeIntervals
end

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: timeinterval' directly reflects the main additions of this changeset: a new timeinterval engine and time interval accessor APIs. It accurately summarizes the primary feature being introduced.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/timeinterval

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 554b559 and b332997.

📒 Files selected for processing (1)
  • properties/properties.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • properties/properties.go

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Fix all issues with AI Agents 🤖
In @properties/properties.go:
- Around line 302-323: The documentation example in the TimeIntervals function
is wrong: it shows a single JSON object but the code unmarshals into
[]timeinterval.TimeInterval; update the comment example to show a JSON array
(e.g. [{"weekdays":["monday:friday"],"times":[...]}]) OR change TimeIntervals to
accept both forms by attempting json.Unmarshal into []timeinterval.TimeInterval
and, on UnmarshalTypeError or if the result is empty, try unmarshalling into a
single timeinterval.TimeInterval and append it to the slice before continuing;
adjust error messages accordingly and keep references to the function
TimeIntervals and the propKey "time_interval."+key.

In @timeinterval/timeinterval.go:
- Around line 445-447: Fix the typo in the comment for the MarshalText method:
change "econding.TextMarshaler" to "encoding.TextMarshaler" in the comment above
the Location.MarshalText function so the doc correctly references the
encoding.TextMarshaler interface.
- Around line 257-259: The error message for the check in the method where you
compare r.Begin and r.End is inverted: when r.Begin > r.End the message should
state the start/begin cannot be after the end, not "before"; update the error
returned in that conditional (the one using r.Begin > r.End) to a correct
message such as "start day cannot be after end day" or "begin cannot be after
end" so it accurately reflects the failing condition.
- Around line 398-401: Fix the typo in the comment above
WeekdayRange.MarshalText: change "econding.TextMarshaler" to
"encoding.TextMarshaler" so the doc correctly references the
encoding.TextMarshaler interface for the MarshalText method on WeekdayRange.
- Around line 609-611: The boundary check currently allows minute value 60
because it uses timeStampMinutes > 60; update the condition in the validation
`if timeStampHours < 0 || timeStampHours > 24 || timeStampMinutes < 0 ||
timeStampMinutes > 60` to use `timeStampMinutes >= 60` (i.e., `... ||
timeStampMinutes >= 60`) so values 60 are rejected; keep the same error return
(`return 0, fmt.Errorf("timestamp %s out of range", in)`) and ensure you update
the condition referencing the variables timeStampHours, timeStampMinutes and the
input `in`.
🧹 Nitpick comments (1)
properties/properties.go (1)

252-254: Returning err when it's guaranteed to be nil is confusing.

At this point, err is always nil (the error case was handled above). Consider returning nil, nil explicitly for clarity.

🔎 Proposed fix
 	if len(hours) == 0 {
-		return nil, err
+		return nil, nil
 	}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d8dbe2 and 457dbc8.

📒 Files selected for processing (2)
  • properties/properties.go
  • timeinterval/timeinterval.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Run linting using make lint to enforce golangci-lint with project-specific rules that disable certain checks for HTTP-related naming
Use the logger package for all logging needs; avoid fmt.Print statements
Use explicit error returns rather than panics
Logger and Properties packages use global instances initialized via Init() functions; always check if initialization is needed before using these packages
When adding new functionality, prefer using existing utilities from within the project (e.g., use collections package for slice operations)

Files:

  • properties/properties.go
  • timeinterval/timeinterval.go
🧠 Learnings (1)
📚 Learning: 2026-01-02T13:47:24.505Z
Learnt from: CR
Repo: flanksource/commons PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T13:47:24.505Z
Learning: Applies to **/*.go : Logger and Properties packages use global instances initialized via `Init()` functions; always check if initialization is needed before using these packages

Applied to files:

  • properties/properties.go
🧬 Code graph analysis (1)
properties/properties.go (1)
timeinterval/timeinterval.go (2)
  • TimeIntervals (61-61)
  • TimeInterval (75-82)
🔇 Additional comments (5)
timeinterval/timeinterval.go (3)

37-53: LGTM!

The Mutes method correctly iterates through named intervals, checks time containment with UTC conversion, and returns matched names. The UTC conversion here works well with the Location handling in ContainsTime.


61-125: LGTM!

Well-structured type definitions with clean use of embedding for the various range types. The TimeInterval struct covers all necessary constraint dimensions.


541-543: Clamp minimum bound appears incorrect for day-of-month calculations.

After converting negative indices to positive on lines 527-536, begin and end are positive values representing actual day numbers. Using -1*daysInMonth as the minimum bound doesn't align with the positive day number domain. The minimum should be 1 to represent valid days.

Although input validation (lines 286-291) likely prevents this from causing issues in practice, the clamping logic could mask bugs or cause unexpected behavior in edge cases.

🔎 Proposed fix
-			begin = clamp(begin, -1*daysInMonth, daysInMonth)
-			end = clamp(end, -1*daysInMonth, daysInMonth)
+			begin = clamp(begin, 1, daysInMonth)
+			end = clamp(end, 1, daysInMonth)
properties/properties.go (2)

69-73: LGTM!

The new import and constant follow the existing patterns in the codebase. The constant businessHoursKey provides a single source of truth for the default key.


259-261: LGTM!

The global wrapper function follows the established pattern used by other accessor functions in this package.

@adityathebe adityathebe changed the title feat/timeinterval feat: timeinterval Jan 5, 2026
@adityathebe adityathebe requested a review from moshloop January 5, 2026 14:34
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (4)
timeinterval/timeinterval.go (4)

257-259: Error message is inverted.

The condition checks r.Begin > r.End, but the error says "start day cannot be before end day". When Begin > End, the start is after the end, not before.

🔎 Proposed fix
 	if r.Begin > r.End {
-		return errors.New("start day cannot be before end day")
+		return errors.New("start day cannot be after end day")
 	}

398-401: Typo in comment: "econding" → "encoding".

🔎 Proposed fix
-// MarshalText implements the econding.TextMarshaler interface for WeekdayRange.
+// MarshalText implements the encoding.TextMarshaler interface for WeekdayRange.

445-447: Typo in comment: "econding" → "encoding".

🔎 Proposed fix
-// MarshalText implements the econding.TextMarshaler interface for Location.
+// MarshalText implements the encoding.TextMarshaler interface for Location.

609-611: Boundary check should use >= 60 for minutes.

The validation timeStampMinutes > 60 incorrectly allows the value 60. Minutes should be in the range 0-59, so the check should be >= 60.

🔎 Proposed fix
-	if timeStampHours < 0 || timeStampHours > 24 || timeStampMinutes < 0 || timeStampMinutes > 60 {
+	if timeStampHours < 0 || timeStampHours > 24 || timeStampMinutes < 0 || timeStampMinutes >= 60 {
🧹 Nitpick comments (1)
timeinterval/timeinterval.go (1)

617-644: Variable name "End" should be lowercase.

On line 629, the variable is named End (capital E), which is inconsistent with Go naming conventions for local variables. It should be end.

🔎 Proposed fix
-		End, err := r.memberFromString(components[1])
+		end, err := r.memberFromString(components[1])
 		if err != nil {
 			return err
 		}
 		r.setBegin(start)
-		r.setEnd(End)
+		r.setEnd(end)
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 457dbc8 and 554b559.

📒 Files selected for processing (2)
  • properties/properties.go
  • timeinterval/timeinterval.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Run linting using make lint to enforce golangci-lint with project-specific rules that disable certain checks for HTTP-related naming
Use the logger package for all logging needs; avoid fmt.Print statements
Use explicit error returns rather than panics
Logger and Properties packages use global instances initialized via Init() functions; always check if initialization is needed before using these packages
When adding new functionality, prefer using existing utilities from within the project (e.g., use collections package for slice operations)

Files:

  • properties/properties.go
  • timeinterval/timeinterval.go
🧠 Learnings (1)
📚 Learning: 2026-01-02T13:47:24.505Z
Learnt from: CR
Repo: flanksource/commons PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T13:47:24.505Z
Learning: Applies to **/*.go : Logger and Properties packages use global instances initialized via `Init()` functions; always check if initialization is needed before using these packages

Applied to files:

  • properties/properties.go
🧬 Code graph analysis (1)
properties/properties.go (1)
timeinterval/timeinterval.go (2)
  • TimeIntervals (61-61)
  • TimeInterval (75-82)
🔇 Additional comments (2)
timeinterval/timeinterval.go (1)

220-246: LGTM: Good Windows platform handling.

The special handling for Windows with the ZONEINFO environment variable is helpful, as Windows doesn't ship with a bundled timezone database by default.

properties/properties.go (1)

302-328: LGTM: Time intervals integration is well-implemented.

The method correctly:

  • Defaults to "business_hours" key when no keys provided
  • Aggregates intervals from multiple property keys
  • Uses appropriate error wrapping with context
  • Skips empty values gracefully

The documentation example now correctly shows array format matching the implementation.

@adityathebe
Copy link
Member Author

adityathebe commented Jan 6, 2026

related:

@moshloop moshloop merged commit dc65ca1 into master Jan 6, 2026
5 checks passed
@moshloop moshloop deleted the feat/timeinterval branch January 6, 2026 07:56
@github-actions
Copy link

github-actions bot commented Jan 6, 2026

🎉 This PR is included in version 1.44.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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.

3 participants