@@ -1069,7 +1069,9 @@ def intersection(self, other):
1069
1069
left_chunk = left .values [lslice ]
1070
1070
return self ._view_like (left_chunk )
1071
1071
1072
- def _partial_date_slice (self , reso , parsed ):
1072
+ def _partial_date_slice (self , reso , parsed , use_lhs = True , use_rhs = True ):
1073
+
1074
+ is_monotonic = self .is_monotonic
1073
1075
1074
1076
if reso == 'year' :
1075
1077
t1 = Timestamp (datetime (parsed .year , 1 , 1 ), tz = self .tz )
@@ -1083,20 +1085,20 @@ def _partial_date_slice(self, reso, parsed):
1083
1085
d = tslib .monthrange (parsed .year , qe )[1 ] # at end of month
1084
1086
t1 = Timestamp (datetime (parsed .year , parsed .month , 1 ), tz = self .tz )
1085
1087
t2 = Timestamp (datetime (parsed .year , qe , d ), tz = self .tz )
1086
- elif reso == 'day' and self ._resolution < Resolution .RESO_DAY :
1088
+ elif ( reso == 'day' and ( self ._resolution < Resolution .RESO_DAY or not is_monotonic )) :
1087
1089
st = datetime (parsed .year , parsed .month , parsed .day )
1088
1090
t1 = Timestamp (st , tz = self .tz )
1089
1091
t2 = st + offsets .Day ()
1090
1092
t2 = Timestamp (Timestamp (t2 , tz = self .tz ).value - 1 )
1091
- elif (reso == 'hour' and
1092
- self ._resolution < Resolution .RESO_HR ):
1093
+ elif (reso == 'hour' and (
1094
+ self ._resolution < Resolution .RESO_HR or not is_monotonic ) ):
1093
1095
st = datetime (parsed .year , parsed .month , parsed .day ,
1094
1096
hour = parsed .hour )
1095
1097
t1 = Timestamp (st , tz = self .tz )
1096
1098
t2 = Timestamp (Timestamp (st + offsets .Hour (),
1097
1099
tz = self .tz ).value - 1 )
1098
- elif (reso == 'minute' and
1099
- self ._resolution < Resolution .RESO_MIN ):
1100
+ elif (reso == 'minute' and (
1101
+ self ._resolution < Resolution .RESO_MIN or not is_monotonic ) ):
1100
1102
st = datetime (parsed .year , parsed .month , parsed .day ,
1101
1103
hour = parsed .hour , minute = parsed .minute )
1102
1104
t1 = Timestamp (st , tz = self .tz )
@@ -1108,15 +1110,18 @@ def _partial_date_slice(self, reso, parsed):
1108
1110
1109
1111
stamps = self .asi8
1110
1112
1111
- if self . is_monotonic :
1113
+ if is_monotonic :
1112
1114
1113
1115
# a monotonic (sorted) series can be sliced
1114
- left = stamps .searchsorted (t1 .value , side = 'left' )
1115
- right = stamps .searchsorted (t2 .value , side = 'right' )
1116
+ left = stamps .searchsorted (t1 .value , side = 'left' ) if use_lhs else None
1117
+ right = stamps .searchsorted (t2 .value , side = 'right' ) if use_rhs else None
1116
1118
return slice (left , right )
1117
1119
1120
+ lhs_mask = (stamps >= t1 .value ) if use_lhs else True
1121
+ rhs_mask = (stamps <= t2 .value ) if use_rhs else True
1122
+
1118
1123
# try to find a the dates
1119
- return (( stamps >= t1 . value ) & ( stamps <= t2 . value ) ).nonzero ()[0 ]
1124
+ return (lhs_mask & rhs_mask ).nonzero ()[0 ]
1120
1125
1121
1126
def _possibly_promote (self , other ):
1122
1127
if other .inferred_type == 'date' :
@@ -1182,11 +1187,11 @@ def get_loc(self, key):
1182
1187
except (KeyError , ValueError ):
1183
1188
raise KeyError (key )
1184
1189
1185
- def _get_string_slice (self , key ):
1190
+ def _get_string_slice (self , key , use_lhs = True , use_rhs = True ):
1186
1191
freq = getattr (self , 'freqstr' ,
1187
1192
getattr (self , 'inferred_freq' , None ))
1188
1193
_ , parsed , reso = parse_time_string (key , freq )
1189
- loc = self ._partial_date_slice (reso , parsed )
1194
+ loc = self ._partial_date_slice (reso , parsed , use_lhs = use_lhs , use_rhs = use_rhs )
1190
1195
return loc
1191
1196
1192
1197
def slice_indexer (self , start = None , end = None , step = None ):
@@ -1208,20 +1213,40 @@ def slice_locs(self, start=None, end=None):
1208
1213
Index.slice_locs, customized to handle partial ISO-8601 string slicing
1209
1214
"""
1210
1215
if isinstance (start , basestring ) or isinstance (end , basestring ):
1211
- try :
1212
- if start :
1213
- start_loc = self ._get_string_slice (start ).start
1214
- else :
1215
- start_loc = 0
1216
1216
1217
- if end :
1218
- end_loc = self ._get_string_slice (end ).stop
1219
- else :
1220
- end_loc = len (self )
1217
+ if self .is_monotonic :
1218
+ try :
1219
+ if start :
1220
+ start_loc = self ._get_string_slice (start ).start
1221
+ else :
1222
+ start_loc = 0
1223
+
1224
+ if end :
1225
+ end_loc = self ._get_string_slice (end ).stop
1226
+ else :
1227
+ end_loc = len (self )
1228
+
1229
+ return start_loc , end_loc
1230
+ except KeyError :
1231
+ pass
1221
1232
1222
- return start_loc , end_loc
1223
- except KeyError :
1224
- pass
1233
+ else :
1234
+ # can't use a slice indexer because we are not sorted!
1235
+ # so create an indexer directly
1236
+ try :
1237
+ if start :
1238
+ start_loc = self ._get_string_slice (start ,use_rhs = False )
1239
+ else :
1240
+ start_loc = np .arange (len (self ))
1241
+
1242
+ if end :
1243
+ end_loc = self ._get_string_slice (end ,use_lhs = False )
1244
+ else :
1245
+ end_loc = np .arange (len (self ))
1246
+
1247
+ return start_loc , end_loc
1248
+ except KeyError :
1249
+ pass
1225
1250
1226
1251
if isinstance (start , time ) or isinstance (end , time ):
1227
1252
raise KeyError ('Cannot use slice_locs with time slice keys' )
0 commit comments