Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,15 @@ def compare_time_range(context_value: Any, condition_value: dict) -> bool:
start_time = current_time.replace(hour=int(start_hour), minute=int(start_min))
end_time = current_time.replace(hour=int(end_hour), minute=int(end_min))

if int(end_hour) < int(start_hour):
# Compare full minutes-since-midnight so that ranges within the same hour (e.g. 23:30 -> 23:00)
# are correctly detected as crossing midnight.
start_minutes = int(start_hour) * 60 + int(start_min)
end_minutes = int(end_hour) * 60 + int(end_min)

if end_minutes < start_minutes:
# In normal circumstances, we need to assert **both** conditions
"""
# When the end hour is smaller than start hour, it means we are crossing a day's boundary.
# When the end time is earlier than start time, it means we are crossing a day's boundary.
# In this case we need to assert that current_time is **either** on one side or the other side of the boundary
#
# ┌─────┐ ┌─────┐ ┌─────┐
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
CONDITION_ACTION = "action"
FEATURE_DEFAULT_VAL_TYPE_KEY = "boolean_type"
TIME_RANGE_FORMAT = "%H:%M" # hour:min 24 hours clock
TIME_RANGE_PATTERN = re.compile(r"2[0-3]:[0-5]\d|[0-1]\d:[0-5]\d") # 24 hour clock
TIME_RANGE_PATTERN = re.compile(r"^(?:2[0-3]|[01]\d):[0-5]\d$") # 24 hour clock, exactly HH:MM
HOUR_MIN_SEPARATOR = ":"
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,9 @@ def test_validate_time_condition_between_time_range_invalid_condition_value_inva
[
{TimeValues.START.value: "11-11", TimeValues.END.value: "23:59"},
{TimeValues.START.value: "24:99", TimeValues.END.value: "23:59"},
{TimeValues.START.value: "10:00abc", TimeValues.END.value: "23:59"}, # trailing garbage
{TimeValues.START.value: "abc10:00", TimeValues.END.value: "23:59"}, # leading garbage
{TimeValues.START.value: "110:00", TimeValues.END.value: "23:59"}, # extra leading digit
],
)
def test_validate_time_condition_between_time_range_invalid_condition_value_invalid_start_time_value(cond_value):
Expand All @@ -549,6 +552,8 @@ def test_validate_time_condition_between_time_range_invalid_condition_value_inva
[
{TimeValues.START.value: "10:11", TimeValues.END.value: "11-11"},
{TimeValues.START.value: "10:11", TimeValues.END.value: "999:59"},
{TimeValues.START.value: "10:11", TimeValues.END.value: "12:00abc"}, # trailing garbage
{TimeValues.START.value: "10:11", TimeValues.END.value: "12:000"}, # extra trailing digit
],
)
def test_validate_time_condition_between_time_range_invalid_condition_value_invalid_end_time_value(cond_value):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,50 @@ def test_time_based_utc_in_between_time_range_between_days_rule_no_match(mocker)
)


def test_time_based_utc_in_between_time_range_same_hour_between_days_rule_match(mocker):
# GIVEN a range whose END is earlier than START but within the same hour (23:30 -> 23:00)
# WHEN the current time is 10:00, which lies inside the range after crossing midnight
# THEN the rule matches
assert evaluate_mocked_schema(
mocker=mocker,
rules={
"lambda time is between UTC 23:30-23:00": {
RULE_MATCH_VALUE: True,
CONDITIONS_KEY: [
{
CONDITION_ACTION: RuleAction.SCHEDULE_BETWEEN_TIME_RANGE.value,
CONDITION_KEY: TimeKeys.CURRENT_TIME.value,
CONDITION_VALUE: {TimeValues.START.value: "23:30", TimeValues.END.value: "23:00"},
},
],
},
},
mocked_time=(2022, 2, 15, 10, 0, 0, datetime.timezone.utc), # rule match 10:00 am
)


def test_time_based_utc_in_between_time_range_same_hour_between_days_rule_no_match(mocker):
# GIVEN a range whose END is earlier than START but within the same hour (23:30 -> 23:00)
# WHEN the current time is 23:15, the only 30-minute gap not covered by the range
# THEN the rule does not match
assert not evaluate_mocked_schema(
mocker=mocker,
rules={
"lambda time is between UTC 23:30-23:00": {
RULE_MATCH_VALUE: True,
CONDITIONS_KEY: [
{
CONDITION_ACTION: RuleAction.SCHEDULE_BETWEEN_TIME_RANGE.value,
CONDITION_KEY: TimeKeys.CURRENT_TIME.value,
CONDITION_VALUE: {TimeValues.START.value: "23:30", TimeValues.END.value: "23:00"},
},
],
},
},
mocked_time=(2022, 2, 15, 23, 15, 0, datetime.timezone.utc), # rule no match 23:15
)


def test_time_based_between_time_range_rule_timezone_match(mocker):
timezone_name = "Europe/Copenhagen"

Expand Down
Loading