@@ -453,32 +453,38 @@ class CustomBusinessDay(BusinessDay):
453
453
_prefix = 'C'
454
454
455
455
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
-
464
456
self .n = int (n )
465
457
self .kwds = kwds
466
458
self .offset = kwds .get ('offset' , timedelta (0 ))
467
459
self .normalize = kwds .get ('normalize' , False )
468
460
self .weekmask = kwds .get ('weekmask' , 'Mon Tue Wed Thu Fri' )
469
-
470
461
holidays = kwds .get ('holidays' , [])
462
+
471
463
holidays = [self ._to_dt64 (dt , dtype = 'datetime64[D]' ) for dt in
472
464
holidays ]
473
465
self .holidays = tuple (sorted (holidays ))
474
466
self .kwds ['holidays' ] = self .holidays
467
+
475
468
self ._set_busdaycalendar ()
476
469
477
470
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
+
482
488
def __getstate__ (self ):
483
489
""""Return a pickleable state"""
484
490
state = self .__dict__ .copy ()
@@ -490,52 +496,71 @@ def __setstate__(self, state):
490
496
self .__dict__ = state
491
497
self ._set_busdaycalendar ()
492
498
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'
499
502
else :
500
- raise TypeError ('dt must be datestring, datetime or datetime64' )
501
- return dt
503
+ roll = 'backward'
502
504
503
- def apply ( self , other ):
505
+ # Distinguish input cases to enhance performance
504
506
if isinstance (other , datetime ):
505
507
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
+
506
525
elif isinstance (other , np .datetime64 ):
507
526
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
+
508
544
elif isinstance (other , (timedelta , Tick )):
509
545
return BDay (self .n , offset = self .offset + other ,
510
546
normalize = self .normalize )
511
547
else :
512
548
raise ApplyTypeError ('Only know how to combine trading day with '
513
549
'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 )
526
550
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
536
561
537
562
def onOffset (self , dt ):
538
- day64 = self ._to_dt64 (dt ). astype ( 'datetime64[D]' )
563
+ day64 = self ._to_dt64 (dt , 'datetime64[D]' )
539
564
return np .is_busday (day64 , busdaycal = self .busdaycalendar )
540
565
541
566
0 commit comments