@@ -15,8 +15,9 @@ const STRICT_INT_MIN: i64 = -9007199254740991;
1515const STRICT_INT_MAX : i64 = 9007199254740991 ;
1616
1717pub const STRICT_INTEGER : u8 = 1 << 0 ;
18+ pub const NAIVE_UTC : u8 = 1 << 1 ;
1819
19- pub const MAX_OPT : i8 = STRICT_INTEGER as i8 ;
20+ pub const MAX_OPT : i8 = STRICT_INTEGER as i8 | NAIVE_UTC as i8 ;
2021
2122const HYPHEN : u8 = 45 ; // "-"
2223const PLUS : u8 = 43 ; // "+"
@@ -177,51 +178,70 @@ impl<'p> Serialize for SerializePyObject {
177178 serializer. serialize_seq ( None ) . unwrap ( ) . end ( )
178179 }
179180 } else if unsafe { obj_ptr == DATETIME_PTR } {
180- if unsafe { ( * ( self . ptr as * mut pyo3:: ffi:: PyDateTime_DateTime ) ) . hastzinfo == 0 } {
181+ if unsafe {
182+ ( * ( self . ptr as * mut pyo3:: ffi:: PyDateTime_DateTime ) ) . hastzinfo == 0
183+ && !self . opts & NAIVE_UTC == NAIVE_UTC
184+ } {
181185 return Err ( ser:: Error :: custom (
182186 "datetime.datetime must have tzinfo set; use datetime.timezone.utc if UTC" ,
183187 ) ) ;
184188 }
185189 let tzinfo = unsafe { pyo3:: ffi:: PyDateTime_DATE_GET_TZINFO ( self . ptr ) } ;
186- let offset: * mut pyo3:: ffi:: PyObject ;
187- if unsafe { pyo3:: ffi:: PyObject_HasAttr ( tzinfo, CONVERT_METHOD_STR ) == 1 } {
188- // pendulum
189- offset = unsafe {
190- pyo3:: ffi:: PyObject_CallMethodObjArgs (
191- self . ptr ,
192- UTCOFFSET_METHOD_STR ,
193- std:: ptr:: null_mut ( ) as * mut pyo3:: ffi:: PyObject ,
194- )
195- } ;
196- } else if unsafe { pyo3:: ffi:: PyObject_HasAttr ( tzinfo, NORMALIZE_METHOD_STR ) == 1 }
197- {
198- // pytz
199- offset = unsafe {
200- pyo3:: ffi:: PyObject_CallMethodObjArgs (
190+ let offset_day: i32 ;
191+ let mut offset_second: i32 ;
192+ if unsafe { ( * ( self . ptr as * mut pyo3:: ffi:: PyDateTime_DateTime ) ) . hastzinfo == 1 } {
193+ if unsafe { pyo3:: ffi:: PyObject_HasAttr ( tzinfo, CONVERT_METHOD_STR ) == 1 } {
194+ // pendulum
195+ let offset = unsafe {
196+ pyo3:: ffi:: PyObject_CallMethodObjArgs (
197+ self . ptr ,
198+ UTCOFFSET_METHOD_STR ,
199+ std:: ptr:: null_mut ( ) as * mut pyo3:: ffi:: PyObject ,
200+ )
201+ } ;
202+ offset_second =
203+ unsafe { pyo3:: ffi:: PyDateTime_DELTA_GET_SECONDS ( offset) as i32 } ;
204+ offset_day = unsafe { pyo3:: ffi:: PyDateTime_DELTA_GET_DAYS ( offset) } ;
205+ } else if unsafe {
206+ pyo3:: ffi:: PyObject_HasAttr ( tzinfo, NORMALIZE_METHOD_STR ) == 1
207+ } {
208+ // pytz
209+ let offset = unsafe {
210+ pyo3:: ffi:: PyObject_CallMethodObjArgs (
211+ pyo3:: ffi:: PyObject_CallMethodObjArgs (
212+ tzinfo,
213+ NORMALIZE_METHOD_STR ,
214+ self . ptr ,
215+ std:: ptr:: null_mut ( ) as * mut pyo3:: ffi:: PyObject ,
216+ ) ,
217+ UTCOFFSET_METHOD_STR ,
218+ std:: ptr:: null_mut ( ) as * mut pyo3:: ffi:: PyObject ,
219+ )
220+ } ;
221+ offset_second =
222+ unsafe { pyo3:: ffi:: PyDateTime_DELTA_GET_SECONDS ( offset) as i32 } ;
223+ offset_day = unsafe { pyo3:: ffi:: PyDateTime_DELTA_GET_DAYS ( offset) } ;
224+ } else if unsafe { pyo3:: ffi:: PyObject_HasAttr ( tzinfo, DST_STR ) == 1 } {
225+ // dateutil/arrow, datetime.timezone.utc
226+ let offset = unsafe {
201227 pyo3:: ffi:: PyObject_CallMethodObjArgs (
202228 tzinfo,
203- NORMALIZE_METHOD_STR ,
229+ UTCOFFSET_METHOD_STR ,
204230 self . ptr ,
205231 std:: ptr:: null_mut ( ) as * mut pyo3:: ffi:: PyObject ,
206- ) ,
207- UTCOFFSET_METHOD_STR ,
208- std:: ptr:: null_mut ( ) as * mut pyo3:: ffi:: PyObject ,
209- )
210- } ;
211- } else if unsafe { pyo3:: ffi:: PyObject_HasAttr ( tzinfo, DST_STR ) == 1 } {
212- // dateutil/arrow, datetime.timezone.utc
213- offset = unsafe {
214- pyo3:: ffi:: PyObject_CallMethodObjArgs (
215- tzinfo,
216- UTCOFFSET_METHOD_STR ,
217- self . ptr ,
218- std:: ptr:: null_mut ( ) as * mut pyo3:: ffi:: PyObject ,
219- )
220- } ;
221- } else {
222- return Err ( ser:: Error :: custom (
232+ )
233+ } ;
234+ offset_second =
235+ unsafe { pyo3:: ffi:: PyDateTime_DELTA_GET_SECONDS ( offset) as i32 } ;
236+ offset_day = unsafe { pyo3:: ffi:: PyDateTime_DELTA_GET_DAYS ( offset) } ;
237+ } else {
238+ return Err ( ser:: Error :: custom (
223239 "datetime's timezone library is not supported: use datetime.timezone.utc, pendulum, pytz, or dateutil" ,
224240 ) ) ;
241+ }
242+ } else {
243+ offset_second = 0 ;
244+ offset_day = 0 ;
225245 } ;
226246
227247 let mut dt: SmallVec < [ u8 ; 32 ] > = SmallVec :: with_capacity ( 32 ) ;
@@ -290,8 +310,6 @@ impl<'p> Serialize for SerializePyObject {
290310 dt. extend ( itoa:: Buffer :: new ( ) . format ( microsecond) . bytes ( ) ) ;
291311 }
292312 }
293- let mut offset_second =
294- unsafe { pyo3:: ffi:: PyDateTime_DELTA_GET_SECONDS ( offset) as i32 } ;
295313 if offset_second == 0 {
296314 dt. push ( PLUS ) ;
297315 dt. push ( ZERO ) ;
@@ -300,7 +318,7 @@ impl<'p> Serialize for SerializePyObject {
300318 dt. push ( ZERO ) ;
301319 dt. push ( ZERO ) ;
302320 } else {
303- if unsafe { pyo3 :: ffi :: PyDateTime_DELTA_GET_DAYS ( offset ) == -1 } {
321+ if offset_day == -1 {
304322 // datetime.timedelta(days=-1, seconds=68400) -> -05:00
305323 dt. push ( HYPHEN ) ;
306324 offset_second = 86400 - offset_second
0 commit comments