|
3 | 3 | (and possibly TimedeltaArray/PeriodArray)
|
4 | 4 | """
|
5 | 5 |
|
6 |
| -from typing import Tuple |
| 6 | +from typing import Union |
7 | 7 |
|
8 | 8 | import numpy as np
|
9 | 9 |
|
10 |
| -from pandas._libs.tslibs import OutOfBoundsDatetime, Timestamp |
| 10 | +from pandas._libs.tslibs import OutOfBoundsDatetime, Timedelta, Timestamp |
11 | 11 |
|
12 |
| -from pandas.tseries.offsets import DateOffset, Tick, generate_range |
| 12 | +from pandas.tseries.offsets import DateOffset |
13 | 13 |
|
14 | 14 |
|
15 | 15 | def generate_regular_range(
|
16 |
| - start: Timestamp, end: Timestamp, periods: int, freq: DateOffset |
17 |
| -) -> Tuple[np.ndarray, str]: |
| 16 | + start: Union[Timestamp, Timedelta], |
| 17 | + end: Union[Timestamp, Timedelta], |
| 18 | + periods: int, |
| 19 | + freq: DateOffset, |
| 20 | +): |
18 | 21 | """
|
19 |
| - Generate a range of dates with the spans between dates described by |
20 |
| - the given `freq` DateOffset. |
| 22 | + Generate a range of dates or timestamps with the spans between dates |
| 23 | + described by the given `freq` DateOffset. |
21 | 24 |
|
22 | 25 | Parameters
|
23 | 26 | ----------
|
24 |
| - start : Timestamp or None |
25 |
| - first point of produced date range |
26 |
| - end : Timestamp or None |
27 |
| - last point of produced date range |
| 27 | + start : Timedelta, Timestamp or None |
| 28 | + First point of produced date range. |
| 29 | + end : Timedelta, Timestamp or None |
| 30 | + Last point of produced date range. |
28 | 31 | periods : int
|
29 |
| - number of periods in produced date range |
30 |
| - freq : DateOffset |
31 |
| - describes space between dates in produced date range |
| 32 | + Number of periods in produced date range. |
| 33 | + freq : Tick |
| 34 | + Describes space between dates in produced date range. |
32 | 35 |
|
33 | 36 | Returns
|
34 | 37 | -------
|
35 |
| - ndarray[np.int64] representing nanosecond unix timestamps |
| 38 | + ndarray[np.int64] Representing nanoseconds. |
36 | 39 | """
|
37 |
| - if isinstance(freq, Tick): |
38 |
| - stride = freq.nanos |
39 |
| - if periods is None: |
40 |
| - b = Timestamp(start).value |
41 |
| - # cannot just use e = Timestamp(end) + 1 because arange breaks when |
42 |
| - # stride is too large, see GH10887 |
43 |
| - e = b + (Timestamp(end).value - b) // stride * stride + stride // 2 + 1 |
44 |
| - # end.tz == start.tz by this point due to _generate implementation |
45 |
| - tz = start.tz |
46 |
| - elif start is not None: |
47 |
| - b = Timestamp(start).value |
48 |
| - e = _generate_range_overflow_safe(b, periods, stride, side="start") |
49 |
| - tz = start.tz |
50 |
| - elif end is not None: |
51 |
| - e = Timestamp(end).value + stride |
52 |
| - b = _generate_range_overflow_safe(e, periods, stride, side="end") |
53 |
| - tz = end.tz |
54 |
| - else: |
55 |
| - raise ValueError( |
56 |
| - "at least 'start' or 'end' should be specified " |
57 |
| - "if a 'period' is given." |
58 |
| - ) |
59 |
| - |
60 |
| - with np.errstate(over="raise"): |
61 |
| - # If the range is sufficiently large, np.arange may overflow |
62 |
| - # and incorrectly return an empty array if not caught. |
63 |
| - try: |
64 |
| - values = np.arange(b, e, stride, dtype=np.int64) |
65 |
| - except FloatingPointError: |
66 |
| - xdr = [b] |
67 |
| - while xdr[-1] != e: |
68 |
| - xdr.append(xdr[-1] + stride) |
69 |
| - values = np.array(xdr[:-1], dtype=np.int64) |
70 |
| - |
| 40 | + start = start.value if start is not None else None |
| 41 | + end = end.value if end is not None else None |
| 42 | + stride = freq.nanos |
| 43 | + |
| 44 | + if periods is None: |
| 45 | + b = start |
| 46 | + # cannot just use e = Timestamp(end) + 1 because arange breaks when |
| 47 | + # stride is too large, see GH10887 |
| 48 | + e = b + (end - b) // stride * stride + stride // 2 + 1 |
| 49 | + elif start is not None: |
| 50 | + b = start |
| 51 | + e = _generate_range_overflow_safe(b, periods, stride, side="start") |
| 52 | + elif end is not None: |
| 53 | + e = end + stride |
| 54 | + b = _generate_range_overflow_safe(e, periods, stride, side="end") |
71 | 55 | else:
|
72 |
| - tz = None |
73 |
| - # start and end should have the same timezone by this point |
74 |
| - if start is not None: |
75 |
| - tz = start.tz |
76 |
| - elif end is not None: |
77 |
| - tz = end.tz |
78 |
| - |
79 |
| - xdr = generate_range(start=start, end=end, periods=periods, offset=freq) |
80 |
| - |
81 |
| - values = np.array([x.value for x in xdr], dtype=np.int64) |
| 56 | + raise ValueError( |
| 57 | + "at least 'start' or 'end' should be specified if a 'period' is given." |
| 58 | + ) |
82 | 59 |
|
83 |
| - return values, tz |
| 60 | + with np.errstate(over="raise"): |
| 61 | + # If the range is sufficiently large, np.arange may overflow |
| 62 | + # and incorrectly return an empty array if not caught. |
| 63 | + try: |
| 64 | + values = np.arange(b, e, stride, dtype=np.int64) |
| 65 | + except FloatingPointError: |
| 66 | + xdr = [b] |
| 67 | + while xdr[-1] != e: |
| 68 | + xdr.append(xdr[-1] + stride) |
| 69 | + values = np.array(xdr[:-1], dtype=np.int64) |
| 70 | + return values |
84 | 71 |
|
85 | 72 |
|
86 | 73 | def _generate_range_overflow_safe(
|
|
0 commit comments