Skip to content
Merged
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
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- `filter_queries` parameter supports text-based filtering on dispatch `id` and `type` fields
- Query format: IDs are prefixed with `#` (e.g., `#4`), types are matched as substrings (e.g., `bar` matches `foobar`)
- Multiple queries are combined with logical OR
* Date-only inputs in CLI timestamps now default to midnight UTC instead of using the current time.

## Bug Fixes

9 changes: 9 additions & 0 deletions src/frequenz/client/dispatch/_cli_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ def convert(
if parse_status == 0:
self.fail(f"Invalid time expression: {value}", param, ctx)

# Check if only a date was provided (no time component)
# parsedatetime returns status 1 for date-only parsing
if parse_status == 1:
# Set time to midnight in UTC for date-only inputs
# First convert to UTC, then set time to midnight
parsed_dt = parsed_dt.astimezone(timezone.utc).replace(
hour=0, minute=0, second=0, microsecond=0
)

return cast(datetime, parsed_dt.astimezone(timezone.utc))
except Exception as e: # pylint: disable=broad-except
self.fail(
Expand Down
28 changes: 28 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
ElectricalComponentCategory,
)
from frequenz.client.dispatch.__main__ import cli
from frequenz.client.dispatch._cli_types import FuzzyDateTime
from frequenz.client.dispatch.recurrence import (
EndCriteria,
Frequency,
Expand Down Expand Up @@ -739,3 +740,30 @@ async def test_delete_command(
assert expected_output in result.output
if dispatches:
assert len(fake_client.dispatches(MicrogridId(1))) == 0


def test_fuzzy_datetime_date_only() -> None:
"""Test that date-only inputs are parsed as midnight."""
fuzzy_dt = FuzzyDateTime()

# Test date-only input
result = fuzzy_dt.convert("2025-08-06", None, None)
assert isinstance(result, datetime)
# Check that time is set to midnight in UTC (accounting for timezone conversion)
# For Europe/Berlin (UTC+2), midnight local time becomes 22:00 UTC previous day
assert result.hour in [
0,
22,
] # Could be 0 (UTC) or 22 (UTC for Europe/Berlin midnight)
assert result.minute == 0
assert result.second == 0
assert result.microsecond == 0

# Test date-time input (should preserve time)
result_with_time = fuzzy_dt.convert("2025-08-06 14:30:15", None, None)
assert isinstance(result_with_time, datetime)
# Time should be preserved (accounting for timezone conversion)
# For Europe/Berlin (UTC+2), 14:30 local becomes 12:30 UTC
assert result_with_time.hour in [12, 14] # Could be 12 (UTC) or 14 (local)
assert result_with_time.minute == 30
assert result_with_time.second == 15