@@ -1731,6 +1731,7 @@ def _get_time_bins(self, ax: DatetimeIndex):
1731
1731
ax .min (),
1732
1732
ax .max (),
1733
1733
self .freq ,
1734
+ unit = ax .unit ,
1734
1735
closed = self .closed ,
1735
1736
origin = self .origin ,
1736
1737
offset = self .offset ,
@@ -1750,7 +1751,8 @@ def _get_time_bins(self, ax: DatetimeIndex):
1750
1751
name = ax .name ,
1751
1752
ambiguous = True ,
1752
1753
nonexistent = "shift_forward" ,
1753
- ).as_unit (ax .unit )
1754
+ unit = ax .unit ,
1755
+ )
1754
1756
1755
1757
ax_values = ax .asi8
1756
1758
binner , bin_edges = self ._adjust_bin_edges (binner , ax_values )
@@ -1960,6 +1962,7 @@ def _get_timestamp_range_edges(
1960
1962
first : Timestamp ,
1961
1963
last : Timestamp ,
1962
1964
freq : BaseOffset ,
1965
+ unit : str ,
1963
1966
closed : Literal ["right" , "left" ] = "left" ,
1964
1967
origin : TimeGrouperOrigin = "start_day" ,
1965
1968
offset : Timedelta | None = None ,
@@ -2015,7 +2018,7 @@ def _get_timestamp_range_edges(
2015
2018
origin = origin .tz_localize (None )
2016
2019
2017
2020
first , last = _adjust_dates_anchored (
2018
- first , last , freq , closed = closed , origin = origin , offset = offset
2021
+ first , last , freq , closed = closed , origin = origin , offset = offset , unit = unit
2019
2022
)
2020
2023
if isinstance (freq , Day ):
2021
2024
first = first .tz_localize (index_tz )
@@ -2082,7 +2085,7 @@ def _get_period_range_edges(
2082
2085
adjust_last = freq .is_on_offset (last_ts )
2083
2086
2084
2087
first_ts , last_ts = _get_timestamp_range_edges (
2085
- first_ts , last_ts , freq , closed = closed , origin = origin , offset = offset
2088
+ first_ts , last_ts , freq , unit = "ns" , closed = closed , origin = origin , offset = offset
2086
2089
)
2087
2090
2088
2091
first = (first_ts + int (adjust_first ) * freq ).to_period (freq )
@@ -2115,32 +2118,42 @@ def _adjust_dates_anchored(
2115
2118
closed : Literal ["right" , "left" ] = "right" ,
2116
2119
origin : TimeGrouperOrigin = "start_day" ,
2117
2120
offset : Timedelta | None = None ,
2121
+ unit = "ns" ,
2118
2122
) -> tuple [Timestamp , Timestamp ]:
2119
2123
# First and last offsets should be calculated from the start day to fix an
2120
2124
# error cause by resampling across multiple days when a one day period is
2121
2125
# not a multiple of the frequency. See GH 8683
2122
2126
# To handle frequencies that are not multiple or divisible by a day we let
2123
2127
# the possibility to define a fixed origin timestamp. See GH 31809
2124
- first = first .as_unit ("ns" )
2125
- last = last .as_unit ("ns" )
2128
+ first = first .as_unit (unit )
2129
+ last = last .as_unit (unit )
2126
2130
if offset is not None :
2127
- offset = offset .as_unit ("ns" )
2128
-
2129
- origin_nanos = 0 # origin == "epoch"
2131
+ offset = offset .as_unit (unit )
2132
+
2133
+ # TODO is there anything which can be reused here?
2134
+ freq_value = freq .nanos
2135
+ if unit == "us" :
2136
+ freq_value = freq_value // 1_000
2137
+ elif unit == "ms" :
2138
+ freq_value = freq_value // 1_000_000
2139
+ elif unit == "s" :
2140
+ freq_value = freq_value // 1_000_000_000
2141
+
2142
+ origin_timestamp = 0 # origin == "epoch"
2130
2143
if origin == "start_day" :
2131
- origin_nanos = first .normalize ()._value
2144
+ origin_timestamp = first .normalize ()._value
2132
2145
elif origin == "start" :
2133
- origin_nanos = first ._value
2146
+ origin_timestamp = first ._value
2134
2147
elif isinstance (origin , Timestamp ):
2135
- origin_nanos = origin .as_unit ("ns" )._value
2148
+ origin_timestamp = origin .as_unit (unit )._value
2136
2149
elif origin in ["end" , "end_day" ]:
2137
2150
origin_last = last if origin == "end" else last .ceil ("D" )
2138
- sub_freq_times = (origin_last ._value - first ._value ) // freq . nanos
2151
+ sub_freq_times = (origin_last ._value - first ._value ) // freq_value
2139
2152
if closed == "left" :
2140
2153
sub_freq_times += 1
2141
2154
first = origin_last - sub_freq_times * freq
2142
- origin_nanos = first ._value
2143
- origin_nanos += offset ._value if offset else 0
2155
+ origin_timestamp = first ._value
2156
+ origin_timestamp += offset ._value if offset else 0
2144
2157
2145
2158
# GH 10117 & GH 19375. If first and last contain timezone information,
2146
2159
# Perform the calculation in UTC in order to avoid localizing on an
@@ -2152,19 +2165,19 @@ def _adjust_dates_anchored(
2152
2165
if last_tzinfo is not None :
2153
2166
last = last .tz_convert ("UTC" )
2154
2167
2155
- foffset = (first ._value - origin_nanos ) % freq . nanos
2156
- loffset = (last ._value - origin_nanos ) % freq . nanos
2168
+ foffset = (first ._value - origin_timestamp ) % freq_value
2169
+ loffset = (last ._value - origin_timestamp ) % freq_value
2157
2170
2158
2171
if closed == "right" :
2159
2172
if foffset > 0 :
2160
2173
# roll back
2161
2174
fresult_int = first ._value - foffset
2162
2175
else :
2163
- fresult_int = first ._value - freq . nanos
2176
+ fresult_int = first ._value - freq_value
2164
2177
2165
2178
if loffset > 0 :
2166
2179
# roll forward
2167
- lresult_int = last ._value + (freq . nanos - loffset )
2180
+ lresult_int = last ._value + (freq_value - loffset )
2168
2181
else :
2169
2182
# already the end of the road
2170
2183
lresult_int = last ._value
@@ -2177,11 +2190,11 @@ def _adjust_dates_anchored(
2177
2190
2178
2191
if loffset > 0 :
2179
2192
# roll forward
2180
- lresult_int = last ._value + (freq . nanos - loffset )
2193
+ lresult_int = last ._value + (freq_value - loffset )
2181
2194
else :
2182
- lresult_int = last ._value + freq . nanos
2183
- fresult = Timestamp (fresult_int )
2184
- lresult = Timestamp (lresult_int )
2195
+ lresult_int = last ._value + freq_value
2196
+ fresult = Timestamp (fresult_int , unit = unit )
2197
+ lresult = Timestamp (lresult_int , unit = unit )
2185
2198
if first_tzinfo is not None :
2186
2199
fresult = fresult .tz_localize ("UTC" ).tz_convert (first_tzinfo )
2187
2200
if last_tzinfo is not None :
0 commit comments