@@ -132,6 +132,34 @@ def hydrate_datetime(seconds, nanoseconds, tz=None):
132132 return zone .localize (t )
133133
134134
135+ def hydrate_datetime_v2 (seconds , nanoseconds , tz = None ):
136+ """ Hydrator for `DateTime` and `LocalDateTime` values.
137+
138+ :param seconds:
139+ :param nanoseconds:
140+ :param tz:
141+ :return: datetime
142+ """
143+ import pytz
144+
145+ minutes , seconds = map (int , divmod (seconds , 60 ))
146+ hours , minutes = map (int , divmod (minutes , 60 ))
147+ days , hours = map (int , divmod (hours , 24 ))
148+ t = DateTime .combine (
149+ Date .from_ordinal (get_date_unix_epoch_ordinal () + days ),
150+ Time (hours , minutes , seconds , nanoseconds )
151+ )
152+ if tz is None :
153+ return t
154+ if isinstance (tz , int ):
155+ tz_offset_minutes , tz_offset_seconds = divmod (tz , 60 )
156+ zone = pytz .FixedOffset (tz_offset_minutes )
157+ else :
158+ zone = pytz .timezone (tz )
159+ t = t .replace (tzinfo = pytz .UTC )
160+ return t .as_timezone (zone )
161+
162+
135163def dehydrate_datetime (value ):
136164 """ Dehydrator for `datetime` values.
137165
@@ -167,8 +195,57 @@ def seconds_and_nanoseconds(dt):
167195 else :
168196 # with time offset
169197 seconds , nanoseconds = seconds_and_nanoseconds (value )
170- return Structure (b"F" , seconds , nanoseconds ,
171- int (tz .utcoffset (value ).total_seconds ()))
198+ offset = tz .utcoffset (value )
199+ if offset .microseconds :
200+ raise ValueError ("Bolt protocol does not support sub-second "
201+ "UTC offsets." )
202+ offset_seconds = offset .days * 86400 + offset .seconds
203+ return Structure (b"F" , seconds , nanoseconds , offset_seconds )
204+
205+
206+ def dehydrate_datetime_v2 (value ):
207+ """ Dehydrator for `datetime` values.
208+
209+ :param value:
210+ :type value: datetime
211+ :return:
212+ """
213+
214+ import pytz
215+
216+ def seconds_and_nanoseconds (dt ):
217+ if isinstance (dt , datetime ):
218+ dt = DateTime .from_native (dt )
219+ dt = dt .astimezone (pytz .UTC )
220+ utc_epoch = DateTime (1970 , 1 , 1 , tzinfo = pytz .UTC )
221+ dt_clock_time = dt .to_clock_time ()
222+ utc_epoch_clock_time = utc_epoch .to_clock_time ()
223+ t = dt_clock_time - utc_epoch_clock_time
224+ return t .seconds , t .nanoseconds
225+
226+ tz = value .tzinfo
227+ if tz is None :
228+ # without time zone
229+ value = pytz .UTC .localize (value )
230+ seconds , nanoseconds = seconds_and_nanoseconds (value )
231+ return Structure (b"d" , seconds , nanoseconds )
232+ elif hasattr (tz , "zone" ) and tz .zone and isinstance (tz .zone , str ):
233+ # with named pytz time zone
234+ seconds , nanoseconds = seconds_and_nanoseconds (value )
235+ return Structure (b"i" , seconds , nanoseconds , tz .zone )
236+ elif hasattr (tz , "key" ) and tz .key and isinstance (tz .key , str ):
237+ # with named zoneinfo (Python 3.9+) time zone
238+ seconds , nanoseconds = seconds_and_nanoseconds (value )
239+ return Structure (b"i" , seconds , nanoseconds , tz .key )
240+ else :
241+ # with time offset
242+ seconds , nanoseconds = seconds_and_nanoseconds (value )
243+ offset = tz .utcoffset (value )
244+ if offset .microseconds :
245+ raise ValueError ("Bolt protocol does not support sub-second "
246+ "UTC offsets." )
247+ offset_seconds = offset .days * 86400 + offset .seconds
248+ return Structure (b"I" , seconds , nanoseconds , offset_seconds )
172249
173250
174251def hydrate_duration (months , days , seconds , nanoseconds ):
0 commit comments