@@ -453,32 +453,38 @@ class CustomBusinessDay(BusinessDay):
453453 _prefix = 'C'
454454
455455 def __init__ (self , n = 1 , ** kwds ):
456- # Check we have the required numpy version
457- from distutils .version import LooseVersion
458-
459- if LooseVersion (np .__version__ ) < '1.7.0' :
460- raise NotImplementedError ("CustomBusinessDay requires numpy >= "
461- "1.7.0. Current version: " +
462- np .__version__ )
463-
464456 self .n = int (n )
465457 self .kwds = kwds
466458 self .offset = kwds .get ('offset' , timedelta (0 ))
467459 self .normalize = kwds .get ('normalize' , False )
468460 self .weekmask = kwds .get ('weekmask' , 'Mon Tue Wed Thu Fri' )
469-
470461 holidays = kwds .get ('holidays' , [])
462+
471463 holidays = [self ._to_dt64 (dt , dtype = 'datetime64[D]' ) for dt in
472464 holidays ]
473465 self .holidays = tuple (sorted (holidays ))
474466 self .kwds ['holidays' ] = self .holidays
467+
475468 self ._set_busdaycalendar ()
476469
477470 def _set_busdaycalendar (self ):
478- holidays = np .array (self .holidays , dtype = 'datetime64[D]' )
479- self .busdaycalendar = np .busdaycalendar (holidays = holidays ,
480- weekmask = self .weekmask )
481-
471+ if self .holidays :
472+ kwargs = {'weekmask' :self .weekmask ,'holidays' :self .holidays }
473+ else :
474+ kwargs = {'weekmask' :self .weekmask }
475+ try :
476+ self .busdaycalendar = np .busdaycalendar (** kwargs )
477+ except :
478+ # Check we have the required numpy version
479+ from distutils .version import LooseVersion
480+
481+ if LooseVersion (np .__version__ ) < '1.7.0' :
482+ raise NotImplementedError ("CustomBusinessDay requires numpy >= "
483+ "1.7.0. Current version: " +
484+ np .__version__ )
485+ else :
486+ raise
487+
482488 def __getstate__ (self ):
483489 """"Return a pickleable state"""
484490 state = self .__dict__ .copy ()
@@ -490,52 +496,71 @@ def __setstate__(self, state):
490496 self .__dict__ = state
491497 self ._set_busdaycalendar ()
492498
493- @staticmethod
494- def _to_dt64 (dt , dtype = 'datetime64' ):
495- if isinstance (dt , (datetime , compat .string_types )):
496- dt = np .datetime64 (dt , dtype = dtype )
497- if isinstance (dt , np .datetime64 ):
498- dt = dt .astype (dtype )
499+ def apply (self , other ):
500+ if self .n <= 0 :
501+ roll = 'forward'
499502 else :
500- raise TypeError ('dt must be datestring, datetime or datetime64' )
501- return dt
503+ roll = 'backward'
502504
503- def apply ( self , other ):
505+ # Distinguish input cases to enhance performance
504506 if isinstance (other , datetime ):
505507 dtype = type (other )
508+ date_in = other
509+ np_dt = np .datetime64 (date_in .date ())
510+
511+ np_incr_dt = np .busday_offset (np_dt , self .n , roll = roll ,
512+ busdaycal = self .busdaycalendar )
513+
514+ dt_date = np_incr_dt .astype (datetime )
515+ if not self .normalize :
516+ result = datetime .combine (dt_date ,date_in .time ())
517+ else :
518+ result = dt_date
519+
520+ if self .offset :
521+ result = result + self .offset
522+
523+ return result
524+
506525 elif isinstance (other , np .datetime64 ):
507526 dtype = other .dtype
527+ date_in = other
528+ np_day = date_in .astype ('datetime64[D]' )
529+ np_time = date_in - np_day
530+
531+ np_incr_dt = np .busday_offset (np_day , self .n , roll = roll ,
532+ busdaycal = self .busdaycalendar )
533+
534+ if not self .normalize :
535+ result = np_day_incr + np_time
536+ else :
537+ result = np_incr_dt
538+
539+ if self .offset :
540+ result = result + self .offset
541+
542+ return result
543+
508544 elif isinstance (other , (timedelta , Tick )):
509545 return BDay (self .n , offset = self .offset + other ,
510546 normalize = self .normalize )
511547 else :
512548 raise ApplyTypeError ('Only know how to combine trading day with '
513549 'datetime, datetime64 or timedelta.' )
514- dt64 = self ._to_dt64 (other )
515-
516- day64 = dt64 .astype ('datetime64[D]' )
517- time = dt64 - day64
518-
519- if self .n <= 0 :
520- roll = 'forward'
521- else :
522- roll = 'backward'
523-
524- result = np .busday_offset (day64 , self .n , roll = roll ,
525- busdaycal = self .busdaycalendar )
526550
527- if not self .normalize :
528- result = result + time
529-
530- result = result .astype (dtype )
531-
532- if self .offset :
533- result = result + self .offset
534-
535- return result
551+ @staticmethod
552+ def _to_dt64 (dt , dtype = 'datetime64' ):
553+ # Currently
554+ # > np.datetime64(dt.datetime(2013,5,1),dtype='datetime64[D]')
555+ # numpy.datetime64('2013-05-01T02:00:00.000000+0200')
556+ # Thus astype is needed to cast datetime to datetime64[D]
557+ dt = np .datetime64 (dt )
558+ if dt .dtype .name != dtype :
559+ dt = dt .astype (dtype )
560+ return dt
536561
537562 def onOffset (self , dt ):
538- day64 = self ._to_dt64 (dt ). astype ( 'datetime64[D]' )
563+ day64 = self ._to_dt64 (dt , 'datetime64[D]' )
539564 return np .is_busday (day64 , busdaycal = self .busdaycalendar )
540565
541566
0 commit comments