1212from datetime import datetime , timedelta , timezone
1313from decimal import Decimal , InvalidOperation
1414from typing import Any , AsyncIterator , Awaitable , Callable , cast
15+ from zoneinfo import ZoneInfo
1516
1617import grpc
1718from frequenz .api .common .v1 .pagination .pagination_params_pb2 import PaginationParams
@@ -129,6 +130,34 @@ async def grpc_call_with_timeout(
129130 raise
130131
131132
133+ def dt_to_pb_timestamp_utc (dt : datetime ) -> Timestamp :
134+ """
135+ Convert a Python datetime object to a UTC Protobuf Timestamp.
136+
137+ The input datetime 'dt' MUST be timezone-aware.
138+
139+ Args:
140+ dt: The Python datetime object to convert.
141+
142+ Returns:
143+ A Protobuf Timestamp object representing the time in UTC.
144+
145+ Raises:
146+ TypeError: If dt is not a datetime.datetime object.
147+ ValueError: If the input datetime object is naive (lacks timezone info).
148+ """
149+ if not isinstance (dt , datetime ):
150+ raise TypeError ("Input must be a datetime.datetime object" )
151+
152+ if dt .tzinfo is None or dt .tzinfo .utcoffset (dt ) is None :
153+ raise ValueError ("Input datetime object must be timezone-aware." )
154+
155+ timestamp = Timestamp ()
156+ timestamp .FromDatetime (dt .astimezone (ZoneInfo ("UTC" )))
157+
158+ return timestamp
159+
160+
132161class Client (BaseApiClient [ElectricityTradingServiceStub ]):
133162 """Electricity trading client."""
134163
@@ -1001,12 +1030,6 @@ def receive_public_order_book(
10011030 Raises:
10021031 grpc.RpcError: If an error occurs while streaming public orders.
10031032 """
1004-
1005- def dt_to_pb_timestamp (dt : datetime ) -> Timestamp :
1006- ts = Timestamp ()
1007- ts .FromDatetime (dt )
1008- return ts
1009-
10101033 public_order_filter = PublicOrderBookFilter (
10111034 delivery_period = delivery_period ,
10121035 delivery_area = delivery_area ,
@@ -1025,12 +1048,14 @@ def dt_to_pb_timestamp(dt: datetime) -> Timestamp:
10251048 electricity_trading_pb2 .ReceivePublicOrderBookStreamRequest (
10261049 filter = public_order_filter .to_pb (),
10271050 start_time = (
1028- dt_to_pb_timestamp (start_time )
1051+ dt_to_pb_timestamp_utc (start_time )
10291052 if start_time
10301053 else None
10311054 ),
10321055 end_time = (
1033- dt_to_pb_timestamp (end_time ) if end_time else None
1056+ dt_to_pb_timestamp_utc (end_time )
1057+ if end_time
1058+ else None
10341059 ),
10351060 ),
10361061 metadata = self ._metadata ,
0 commit comments