@@ -66,9 +66,7 @@ def __new__(cls, start=None, end=None, periods=None,
66
66
end = datetools .to_datetime (end )
67
67
68
68
# inside cache range. Handle UTC case
69
-
70
- useCache = (offset .isAnchored () and
71
- isinstance (offset , datetools .CacheableOffset ))
69
+ useCache = _will_use_cache (offset )
72
70
73
71
start , end , tzinfo = _figure_out_timezone (start , end , tzinfo )
74
72
useCache = useCache and _naive_in_cache_range (start , end )
@@ -285,16 +283,72 @@ def union(self, other):
285
283
else :
286
284
left , right = other , self
287
285
288
- left_start , left_end = left [ 0 ], left [- 1 ]
289
- right_start , right_end = right [0 ], right [ - 1 ]
286
+ left_end = left [- 1 ]
287
+ right_start = right [0 ]
290
288
291
289
# Only need to "adjoin", not overlap
292
290
if (left_end + offset ) >= right_start :
293
- return DateRange (left_start , max (left_end , right_end ),
294
- offset = offset )
291
+ return left ._fast_union (right )
295
292
else :
296
293
return Index .union (self , other )
297
294
295
+ def intersection (self , other ):
296
+ """
297
+ Specialized intersection for DateRange objects. May be much faster than
298
+ Index.union
299
+
300
+ Parameters
301
+ ----------
302
+ other : DateRange or array-like
303
+
304
+ Returns
305
+ -------
306
+ y : Index or DateRange
307
+ """
308
+ if not isinstance (other , DateRange ) or other .offset != self .offset :
309
+ return Index .intersection (self .view (Index ), other )
310
+
311
+ # to make our life easier, "sort" the two ranges
312
+ if self [0 ] <= other [0 ]:
313
+ left , right = self , other
314
+ else :
315
+ left , right = other , self
316
+
317
+ left_end = left [- 1 ]
318
+ right_start = right [0 ]
319
+
320
+ if left_end < right_start :
321
+ return Index ([])
322
+ else :
323
+ lslice = slice (* left .slice_locs (right_start , None ))
324
+ left_chunk = left .values [lslice ]
325
+ return self ._view_like (left_chunk )
326
+
327
+ def _fast_union (self , other ):
328
+ left , right = self , other
329
+
330
+ left_start , left_end = left [0 ], left [- 1 ]
331
+ right_end = right [- 1 ]
332
+
333
+ if not _will_use_cache (self .offset ):
334
+ # concatenate dates
335
+ if left_end < right_end :
336
+ loc = right .searchsorted (left_end , side = 'right' )
337
+ right_chunk = right .values [loc :]
338
+ dates = np .concatenate ((left .values , right_chunk ))
339
+ return self ._view_like (dates )
340
+ else :
341
+ return left
342
+ else :
343
+ return DateRange (left_start , max (left_end , right_end ),
344
+ offset = left .offset )
345
+
346
+ def _view_like (self , ndarray ):
347
+ result = ndarray .view (DateRange )
348
+ result .offset = self .offset
349
+ result .tzinfo = self .tzinfo
350
+ return result
351
+
298
352
def _wrap_union_result (self , other , result ):
299
353
return Index (result )
300
354
@@ -484,6 +538,11 @@ def _infer(a, b):
484
538
tz = _infer (end , start )
485
539
return tz
486
540
541
+ def _will_use_cache (offset ):
542
+ return (offset .isAnchored () and
543
+ isinstance (offset , datetools .CacheableOffset ))
544
+
545
+
487
546
if __name__ == '__main__' :
488
547
import pytz
489
548
# just want it to work
0 commit comments