Time-Based Rules¶
Rules can include temporal conditions that match on the current time at dispatch. This enables patterns like business-hours suppression, weekend rerouting, and maintenance-window controls without external schedulers.
How It Works¶
The rule engine exposes a time identifier containing the current timestamp broken into components. You can use time.* fields in conditions just like action.* fields — no special syntax or configuration required. By default, time.* fields use UTC, but you can configure a timezone at the gateway or per-rule level.
Available Fields¶
| Field | Type | Range | Description |
|---|---|---|---|
time.hour | int | 0–23 | Hour of the day |
time.minute | int | 0–59 | Minute of the hour |
time.second | int | 0–59 | Second of the minute |
time.day | int | 1–31 | Day of the month |
time.month | int | 1–12 | Month of the year |
time.year | int | — | Four-digit year |
time.weekday | string | — | English name ("Monday" … "Sunday") |
time.weekday_num | int | 1–7 | ISO weekday (1=Monday … 7=Sunday) |
time.timestamp | int | — | Unix timestamp in seconds |
Note
By default, all temporal values (except timestamp) use UTC. Use the timezone field on a rule or the default_timezone gateway setting to evaluate in a specific timezone. The timestamp field always returns the UTC unix timestamp regardless of timezone.
Prefer weekday_num for programmatic logic
The weekday field returns English names ("Monday", etc.) which are convenient for readability but hardcode a locale. Use weekday_num (1=Monday … 7=Sunday) for conditions that should be language-independent.
Timezone Support¶
Rules can specify an IANA timezone (e.g. "US/Eastern", "Europe/Berlin") so that time.* fields are evaluated in local time. This avoids manual UTC offset calculations and correctly handles DST transitions.
DST edge cases
During "spring forward" transitions, time.hour == 2 may never occur (the clock jumps from 1:59 to 3:00). During "fall back", time.hour == 1 occurs twice. Avoid exact-hour equality checks near DST boundaries. Range checks like time.hour >= 9 && time.hour < 17 are safe because business hours don't overlap the 1–3 AM DST window.
Resolution order (most specific wins):
- Per-rule
timezonefield - Gateway-level
default_timezone(set inacteon.tomlunder[rules]) - UTC (implicit default)
Per-Rule Timezone¶
rules:
- name: business-hours-eastern
timezone: "US/Eastern"
condition:
all:
- field: time.hour
gte: 9
- field: time.hour
lt: 17
- field: time.weekday_num
lte: 5
action:
type: allow
Gateway Default Timezone¶
Set in acteon.toml:
All rules without an explicit timezone field will use US/Eastern for time.* fields.
CEL with Timezone¶
rules:
- name: business-hours-eastern
timezone: "US/Eastern"
condition: 'time.hour >= 9 && time.hour < 17 && time.weekday_num <= 5'
action:
type: allow
YAML Examples¶
Suppress Outside Business Hours¶
rules:
- name: suppress-outside-hours
priority: 1
description: "Suppress non-critical notifications outside 9-17 UTC"
condition:
any:
- field: time.hour
lt: 9
- field: time.hour
gte: 17
action:
type: suppress
Suppress on Weekends¶
rules:
- name: suppress-weekends
priority: 2
description: "Suppress notifications on Saturday and Sunday"
condition:
field: time.weekday_num
gt: 5
action:
type: suppress
Reroute to On-Call During Off-Hours¶
rules:
- name: reroute-off-hours-to-oncall
priority: 3
description: "Reroute alerts to PagerDuty outside business hours"
condition:
all:
- field: action.action_type
eq: "alert"
- any:
- field: time.hour
lt: 9
- field: time.hour
gte: 17
action:
type: reroute
target_provider: pagerduty
Combined: Business Hours + Weekdays Only¶
rules:
- name: business-hours-only
priority: 1
description: "Suppress outside Mon-Fri 9-17 UTC"
condition:
any:
- field: time.weekday_num
gt: 5
- field: time.hour
lt: 9
- field: time.hour
gte: 17
action:
type: suppress
Weekday Name Matching¶
rules:
- name: suppress-saturday
priority: 1
condition:
field: time.weekday
eq: "Saturday"
action:
type: suppress
CEL Examples¶
The same conditions work in CEL rule files with natural expression syntax:
rules:
- name: suppress-outside-hours
priority: 1
condition: 'time.hour < 9 || time.hour >= 17'
action:
type: suppress
- name: business-hours-weekdays
priority: 2
condition: 'time.hour >= 9 && time.hour < 17 && time.weekday_num <= 5'
action:
type: allow
- name: reroute-night-alerts
priority: 3
condition: 'action.action_type == "alert" && (time.hour < 6 || time.hour >= 22)'
action:
type: reroute
target_provider: pagerduty
- name: suppress-weekends
priority: 4
condition: 'time.weekday == "Saturday" || time.weekday == "Sunday"'
action:
type: suppress
Combining with Action Fields¶
Time conditions compose freely with action-based conditions:
rules:
- name: throttle-night-email
priority: 5
description: "Throttle email during off-hours to avoid inbox flooding"
condition:
all:
- field: action.action_type
eq: "send_email"
- any:
- field: time.hour
lt: 8
- field: time.hour
gte: 20
action:
type: throttle
max_count: 10
window_seconds: 3600
Testing with Dry-Run¶
Use dry-run mode to verify time-based rules behave as expected:
curl -s -X POST "http://localhost:8080/v1/dispatch?dry_run=true" \
-H "Content-Type: application/json" \
-d '{
"namespace": "notifications",
"tenant": "tenant-1",
"provider": "email",
"action_type": "send_email",
"payload": {"to": "user@example.com"}
}' | jq .
The response shows which rule matched and what the verdict would be at the current time.
Simulation¶
See Also¶
- Rule System — full rule system overview
- YAML Rule Reference — complete syntax reference
- Dry-Run Mode — testing rules without executing