@@ -483,25 +483,20 @@ def get_value(self, series, key):
483483 return series .iat [key ]
484484
485485 if isinstance (key , str ):
486+ try :
487+ loc = self ._get_string_slice (key )
488+ return series [loc ]
489+ except (TypeError , ValueError ):
490+ pass
491+
486492 asdt , reso = parse_time_string (key , self .freq )
487493 grp = resolution .Resolution .get_freq_group (reso )
488494 freqn = resolution .get_freq_group (self .freq )
489495
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
497498
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 :
505500 key = Period (asdt , freq = self .freq )
506501 loc = self .get_loc (key )
507502 return series .iloc [loc ]
@@ -643,61 +638,39 @@ def _maybe_cast_slice_bound(self, label, side, kind):
643638
644639 return label
645640
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" ]:
684643 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" ))
686648
687649 def _get_string_slice (self , key : str , use_lhs : bool = True , use_rhs : bool = True ):
688650 # TODO: Check for non-True use_lhs/use_rhs
651+ raw = key
689652 if not self .is_monotonic :
690653 raise ValueError ("Partial indexing only valid for ordered time series" )
691654
692655 parsed , reso = parse_time_string (key , self .freq )
693656 grp = resolution .Resolution .get_freq_group (reso )
694657 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 )
697664
698665 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
699671 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" ),
701674 )
702675
703676 def _convert_tolerance (self , tolerance , target ):
0 commit comments