@@ -483,25 +483,20 @@ def get_value(self, series, key):
483
483
return series .iat [key ]
484
484
485
485
if isinstance (key , str ):
486
+ try :
487
+ loc = self ._get_string_slice (key )
488
+ return series [loc ]
489
+ except (TypeError , ValueError ):
490
+ pass
491
+
486
492
asdt , reso = parse_time_string (key , self .freq )
487
493
grp = resolution .Resolution .get_freq_group (reso )
488
494
freqn = resolution .get_freq_group (self .freq )
489
495
490
- vals = self ._ndarray_values
491
-
492
- # if our data is higher resolution than requested key, slice
493
- if grp < freqn :
494
- iv = Period (asdt , freq = (grp , 1 ))
495
- ord1 = iv .asfreq (self .freq , how = "S" ).ordinal
496
- ord2 = iv .asfreq (self .freq , how = "E" ).ordinal
496
+ # _get_string_slice will handle cases where grp < freqn
497
+ assert grp >= freqn
497
498
498
- if ord2 < vals [0 ] or ord1 > vals [- 1 ]:
499
- raise KeyError (key )
500
-
501
- pos = np .searchsorted (self ._ndarray_values , [ord1 , ord2 ])
502
- key = slice (pos [0 ], pos [1 ] + 1 )
503
- return series [key ]
504
- elif grp == freqn :
499
+ if grp == freqn :
505
500
key = Period (asdt , freq = self .freq )
506
501
loc = self .get_loc (key )
507
502
return series .iloc [loc ]
@@ -643,61 +638,39 @@ def _maybe_cast_slice_bound(self, label, side, kind):
643
638
644
639
return label
645
640
646
- def _parsed_string_to_bounds (self , reso , parsed ):
647
- if reso == "year" :
648
- t1 = Period (year = parsed .year , freq = "A" )
649
- elif reso == "month" :
650
- t1 = Period (year = parsed .year , month = parsed .month , freq = "M" )
651
- elif reso == "quarter" :
652
- q = (parsed .month - 1 ) // 3 + 1
653
- t1 = Period (year = parsed .year , quarter = q , freq = "Q-DEC" )
654
- elif reso == "day" :
655
- t1 = Period (year = parsed .year , month = parsed .month , day = parsed .day , freq = "D" )
656
- elif reso == "hour" :
657
- t1 = Period (
658
- year = parsed .year ,
659
- month = parsed .month ,
660
- day = parsed .day ,
661
- hour = parsed .hour ,
662
- freq = "H" ,
663
- )
664
- elif reso == "minute" :
665
- t1 = Period (
666
- year = parsed .year ,
667
- month = parsed .month ,
668
- day = parsed .day ,
669
- hour = parsed .hour ,
670
- minute = parsed .minute ,
671
- freq = "T" ,
672
- )
673
- elif reso == "second" :
674
- t1 = Period (
675
- year = parsed .year ,
676
- month = parsed .month ,
677
- day = parsed .day ,
678
- hour = parsed .hour ,
679
- minute = parsed .minute ,
680
- second = parsed .second ,
681
- freq = "S" ,
682
- )
683
- else :
641
+ def _parsed_string_to_bounds (self , reso : str , parsed : datetime ):
642
+ if reso not in ["year" , "month" , "quarter" , "day" , "hour" , "minute" , "second" ]:
684
643
raise KeyError (reso )
685
- return (t1 .asfreq (self .freq , how = "start" ), t1 .asfreq (self .freq , how = "end" ))
644
+
645
+ grp = resolution .Resolution .get_freq_group (reso )
646
+ iv = Period (parsed , freq = (grp , 1 ))
647
+ return (iv .asfreq (self .freq , how = "start" ), iv .asfreq (self .freq , how = "end" ))
686
648
687
649
def _get_string_slice (self , key : str , use_lhs : bool = True , use_rhs : bool = True ):
688
650
# TODO: Check for non-True use_lhs/use_rhs
651
+ raw = key
689
652
if not self .is_monotonic :
690
653
raise ValueError ("Partial indexing only valid for ordered time series" )
691
654
692
655
parsed , reso = parse_time_string (key , self .freq )
693
656
grp = resolution .Resolution .get_freq_group (reso )
694
657
freqn = resolution .get_freq_group (self .freq )
695
- if reso in ["day" , "hour" , "minute" , "second" ] and not grp < freqn :
696
- raise KeyError (key )
658
+
659
+ if not grp < freqn :
660
+ # TODO: we used to also check for
661
+ # reso in ["day", "hour", "minute", "second"]
662
+ # why is that check not needed?
663
+ raise TypeError (key )
697
664
698
665
t1 , t2 = self ._parsed_string_to_bounds (reso , parsed )
666
+ if len (self ):
667
+ if t2 < self .min () or t1 > self .max ():
668
+ raise KeyError (raw )
669
+
670
+ # Use asi8 searchsorted to avoid overhead of re-validating inputs
699
671
return slice (
700
- self .searchsorted (t1 , side = "left" ), self .searchsorted (t2 , side = "right" )
672
+ self .asi8 .searchsorted (t1 .ordinal , side = "left" ),
673
+ self .asi8 .searchsorted (t2 .ordinal , side = "right" ),
701
674
)
702
675
703
676
def _convert_tolerance (self , tolerance , target ):
0 commit comments