@@ -30,6 +30,10 @@ private Converter()
3030 private static Type flagsType ;
3131 private static Type boolType ;
3232 private static Type typeType ;
33+ private static IntPtr decimalCtor ;
34+ private static IntPtr dateTimeCtor ;
35+ private static IntPtr timeSpanCtor ;
36+ private static IntPtr tzInfoCtor ;
3337
3438 static Converter ( )
3539 {
@@ -45,6 +49,38 @@ static Converter()
4549 flagsType = typeof ( FlagsAttribute ) ;
4650 boolType = typeof ( Boolean ) ;
4751 typeType = typeof ( Type ) ;
52+
53+
54+ IntPtr decimalMod = Runtime . PyImport_ImportModule ( "decimal" ) ;
55+ if ( decimalMod == null ) throw new PythonException ( ) ;
56+
57+ IntPtr dateTimeMod = Runtime . PyImport_ImportModule ( "datetime" ) ;
58+ if ( dateTimeMod == null ) throw new PythonException ( ) ;
59+
60+ decimalCtor = Runtime . PyObject_GetAttrString ( decimalMod , "Decimal" ) ;
61+ if ( decimalCtor == null ) throw new PythonException ( ) ;
62+
63+ dateTimeCtor = Runtime . PyObject_GetAttrString ( dateTimeMod , "datetime" ) ;
64+ if ( dateTimeCtor == null ) throw new PythonException ( ) ;
65+
66+ timeSpanCtor = Runtime . PyObject_GetAttrString ( dateTimeMod , "timedelta" ) ;
67+ if ( timeSpanCtor == null ) throw new PythonException ( ) ;
68+
69+ IntPtr tzInfoMod = PythonEngine . ModuleFromString ( "custom_tzinfo" ,
70+ "from datetime import timedelta, tzinfo\n " +
71+ "class GMT(tzinfo):\n " +
72+ " def __init__(self, hours, minutes):\n " +
73+ " self.hours = hours\n " +
74+ " self.minutes = minutes\n " +
75+ " def utcoffset(self, dt):\n " +
76+ " return timedelta(hours=self.hours, minutes=self.minutes)\n " +
77+ " def tzname(self, dt):\n " +
78+ " return \" GMT {0:00}:{1:00}\" .format(self.hours, self.minutes)\n " +
79+ " def dst (self, dt):\n " +
80+ " return timedelta(0)\n " ) . Handle ;
81+
82+ tzInfoCtor = Runtime . PyObject_GetAttrString ( tzInfoMod , "GMT" ) ;
83+ if ( tzInfoCtor == null ) throw new PythonException ( ) ;
4884 }
4985
5086
@@ -208,6 +244,14 @@ internal static IntPtr ToPython(object value, Type type)
208244 switch ( tc )
209245 {
210246 case TypeCode . Object :
247+ if ( value is TimeSpan )
248+ {
249+ var timespan = ( TimeSpan ) value ;
250+
251+ IntPtr timeSpanArgs = Runtime . PyTuple_New ( 1 ) ;
252+ Runtime . PyTuple_SetItem ( timeSpanArgs , 0 , Runtime . PyFloat_FromDouble ( timespan . TotalDays ) ) ;
253+ return Runtime . PyObject_CallObject ( timeSpanCtor , timeSpanArgs ) ;
254+ }
211255 return CLRObject . GetInstHandle ( value , type ) ;
212256
213257 case TypeCode . String :
@@ -269,7 +313,23 @@ internal static IntPtr ToPython(object value, Type type)
269313 IntPtr args = Runtime . PyTuple_New ( 1 ) ;
270314 Runtime . PyTuple_SetItem ( args , 0 , d2p ) ;
271315
272- return Runtime . PyObject_CallObject ( ctor , args ) ;
316+ return Runtime . PyObject_CallObject ( decimalCtor , args ) ;
317+
318+ case TypeCode . DateTime :
319+ var datetime = ( DateTime ) value ;
320+
321+ IntPtr dateTimeArgs = Runtime . PyTuple_New ( 8 ) ;
322+ Runtime . PyTuple_SetItem ( dateTimeArgs , 0 , Runtime . PyInt_FromInt32 ( datetime . Year ) ) ;
323+ Runtime . PyTuple_SetItem ( dateTimeArgs , 1 , Runtime . PyInt_FromInt32 ( datetime . Month ) ) ;
324+ Runtime . PyTuple_SetItem ( dateTimeArgs , 2 , Runtime . PyInt_FromInt32 ( datetime . Day ) ) ;
325+ Runtime . PyTuple_SetItem ( dateTimeArgs , 3 , Runtime . PyInt_FromInt32 ( datetime . Hour ) ) ;
326+ Runtime . PyTuple_SetItem ( dateTimeArgs , 4 , Runtime . PyInt_FromInt32 ( datetime . Minute ) ) ;
327+ Runtime . PyTuple_SetItem ( dateTimeArgs , 5 , Runtime . PyInt_FromInt32 ( datetime . Second ) ) ;
328+ Runtime . PyTuple_SetItem ( dateTimeArgs , 6 , Runtime . PyInt_FromInt32 ( datetime . Millisecond ) ) ;
329+ Runtime . PyTuple_SetItem ( dateTimeArgs , 7 , TzInfo ( datetime . Kind ) ) ;
330+
331+ return Runtime . PyObject_CallObject ( dateTimeCtor , dateTimeArgs ) ;
332+
273333
274334 default :
275335 if ( value is IEnumerable )
@@ -292,6 +352,15 @@ internal static IntPtr ToPython(object value, Type type)
292352 }
293353 }
294354
355+ private static IntPtr TzInfo ( DateTimeKind kind )
356+ {
357+ if ( kind == DateTimeKind . Unspecified ) return Runtime . PyNone ;
358+ var offset = kind == DateTimeKind . Local ? DateTimeOffset . Now . Offset : TimeSpan . Zero ;
359+ IntPtr tzInfoArgs = Runtime . PyTuple_New ( 2 ) ;
360+ Runtime . PyTuple_SetItem ( tzInfoArgs , 0 , Runtime . PyFloat_FromDouble ( offset . Hours ) ) ;
361+ Runtime . PyTuple_SetItem ( tzInfoArgs , 1 , Runtime . PyFloat_FromDouble ( offset . Minutes ) ) ;
362+ return Runtime . PyObject_CallObject ( tzInfoCtor , tzInfoArgs ) ;
363+ }
295364
296365 /// <summary>
297366 /// In a few situations, we don't have any advisory type information
@@ -507,6 +576,12 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
507576 return false ;
508577 }
509578
579+ var underlyingType = Nullable . GetUnderlyingType ( obType ) ;
580+ if ( underlyingType != null )
581+ {
582+ return ToManagedValue ( value , underlyingType , out result , setError ) ;
583+ }
584+
510585 TypeCode typeCode = Type . GetTypeCode ( obType ) ;
511586 if ( typeCode == TypeCode . Object )
512587 {
@@ -533,6 +608,32 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
533608
534609 switch ( tc )
535610 {
611+ case TypeCode . Object :
612+ if ( obType == typeof ( TimeSpan ) )
613+ {
614+ op = Runtime . PyObject_Str ( value ) ;
615+ TimeSpan ts ;
616+ var arr = Runtime . GetManagedString ( op ) . Split ( ',' ) ;
617+ string sts = arr . Length == 1 ? arr [ 0 ] : arr [ 1 ] ;
618+ if ( ! TimeSpan . TryParse ( sts , out ts ) )
619+ {
620+ goto type_error ;
621+ }
622+ Runtime . XDecref ( op ) ;
623+
624+ int days = 0 ;
625+ if ( arr . Length > 1 )
626+ {
627+ if ( ! int . TryParse ( arr [ 0 ] . Split ( ' ' ) [ 0 ] . Trim ( ) , out days ) )
628+ {
629+ goto type_error ;
630+ }
631+ }
632+ result = ts . Add ( TimeSpan . FromDays ( days ) ) ;
633+ return true ;
634+ }
635+ break ;
636+
536637 case TypeCode . String :
537638 string st = Runtime . GetManagedString ( value ) ;
538639 if ( st == null )
@@ -774,6 +875,17 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
774875 Runtime . XDecref ( op ) ;
775876 result = m ;
776877 return true ;
878+ case TypeCode . DateTime :
879+ op = Runtime . PyObject_Str ( value ) ;
880+ DateTime dt ;
881+ string sdt = Runtime . GetManagedString ( op ) ;
882+ if ( ! DateTime . TryParse ( sdt , out dt ) )
883+ {
884+ goto type_error ;
885+ }
886+ Runtime . XDecref ( op ) ;
887+ result = dt ;
888+ return true ;
777889 default :
778890 goto type_error ;
779891 }
0 commit comments