refactor(formatters, get_chartdata): serialize datetime objects to ISO format in data points

This commit is contained in:
Julian Pawlowski 2025-11-30 15:07:18 +00:00
parent 09eb9c7050
commit 6f93bb8288
2 changed files with 36 additions and 9 deletions

View file

@ -166,7 +166,12 @@ def aggregate_hourly_exact( # noqa: PLR0913, PLR0912, PLR0915
if round_decimals is not None: if round_decimals is not None:
avg_price = round(avg_price, round_decimals) avg_price = round(avg_price, round_decimals)
data_point = {start_time_field: start_time_str, price_field: avg_price} data_point = {
start_time_field: start_time_str.isoformat()
if hasattr(start_time_str, "isoformat")
else start_time_str,
price_field: avg_price,
}
# Add aggregated level using same logic as sensors # Add aggregated level using same logic as sensors
if include_level and hour_interval_data: if include_level and hour_interval_data:
@ -295,10 +300,12 @@ def get_period_data( # noqa: PLR0913, PLR0912, PLR0915
data_point = {} data_point = {}
# Start time # Start time
data_point[start_time_field] = period["start"] start = period["start"]
data_point[start_time_field] = start.isoformat() if hasattr(start, "isoformat") else start
# End time # End time
data_point[end_time_field] = period.get("end") end = period.get("end")
data_point[end_time_field] = end.isoformat() if end and hasattr(end, "isoformat") else end
# Price (use price_avg from period, stored in minor units) # Price (use price_avg from period, stored in minor units)
price_avg = period.get("price_avg", 0.0) price_avg = period.get("price_avg", 0.0)
@ -327,7 +334,9 @@ def get_period_data( # noqa: PLR0913, PLR0912, PLR0915
price_avg = price_avg / 100 price_avg = price_avg / 100
if round_decimals is not None: if round_decimals is not None:
price_avg = round(price_avg, round_decimals) price_avg = round(price_avg, round_decimals)
chart_data.append([period["start"], price_avg]) start = period["start"]
start_serialized = start.isoformat() if hasattr(start, "isoformat") else start
chart_data.append([start_serialized, price_avg])
# Add trailing null point if requested # Add trailing null point if requested
if add_trailing_null and chart_data: if add_trailing_null and chart_data:

View file

@ -306,7 +306,10 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091
if round_decimals is not None: if round_decimals is not None:
price = round(price, round_decimals) price = round(price, round_decimals)
data_point = {start_time_field: start_time, price_field: price} data_point = {
start_time_field: start_time.isoformat() if hasattr(start_time, "isoformat") else start_time,
price_field: price,
}
# Add level if requested (only when price is not NULL) # Add level if requested (only when price is not NULL)
if include_level and "level" in interval and price is not None: if include_level and "level" in interval and price is not None:
@ -349,7 +352,12 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091
converted_price = round(converted_price, round_decimals) converted_price = round(converted_price, round_decimals)
# Add current point # Add current point
data_point = {start_time_field: start_time, price_field: converted_price} data_point = {
start_time_field: start_time.isoformat()
if hasattr(start_time, "isoformat")
else start_time,
price_field: converted_price,
}
if include_level and "level" in interval: if include_level and "level" in interval:
data_point[level_field] = interval["level"] data_point[level_field] = interval["level"]
@ -363,7 +371,12 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091
# Check if next interval is different level (segment boundary) # Check if next interval is different level (segment boundary)
if next_value != interval_value: if next_value != interval_value:
# Hold current price until next timestamp (stepline effect) # Hold current price until next timestamp (stepline effect)
hold_point = {start_time_field: next_start_time, price_field: converted_price} next_start_serialized = (
next_start_time.isoformat()
if next_start_time and hasattr(next_start_time, "isoformat")
else next_start_time
)
hold_point = {start_time_field: next_start_serialized, price_field: converted_price}
if include_level and "level" in interval: if include_level and "level" in interval:
hold_point[level_field] = interval["level"] hold_point[level_field] = interval["level"]
if include_rating_level and "rating_level" in interval: if include_rating_level and "rating_level" in interval:
@ -373,7 +386,7 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091
chart_data.append(hold_point) chart_data.append(hold_point)
# Add NULL point to create gap # Add NULL point to create gap
null_point = {start_time_field: next_start_time, price_field: None} null_point = {start_time_field: next_start_serialized, price_field: None}
chart_data.append(null_point) chart_data.append(null_point)
# Handle last interval of the day - extend to midnight # Handle last interval of the day - extend to midnight
@ -472,7 +485,12 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091
if round_decimals is not None: if round_decimals is not None:
price = round(price, round_decimals) price = round(price, round_decimals)
data_point = {start_time_field: start_time, price_field: price} data_point = {
start_time_field: start_time.isoformat()
if hasattr(start_time, "isoformat")
else start_time,
price_field: price,
}
# Add level if requested # Add level if requested
if include_level and "level" in interval: if include_level and "level" in interval: