Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pandas/core/indexes/accessors.py: 34%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

140 statements  

1""" 

2datetimelike delegation 

3""" 

4from __future__ import annotations 

5 

6from typing import ( 

7 TYPE_CHECKING, 

8 cast, 

9) 

10 

11import numpy as np 

12 

13from pandas.core.dtypes.common import ( 

14 is_categorical_dtype, 

15 is_datetime64_dtype, 

16 is_datetime64tz_dtype, 

17 is_integer_dtype, 

18 is_list_like, 

19 is_period_dtype, 

20 is_timedelta64_dtype, 

21) 

22from pandas.core.dtypes.generic import ABCSeries 

23 

24from pandas.core.accessor import ( 

25 PandasDelegate, 

26 delegate_names, 

27) 

28from pandas.core.arrays import ( 

29 DatetimeArray, 

30 PeriodArray, 

31 TimedeltaArray, 

32) 

33from pandas.core.arrays.arrow.array import ArrowExtensionArray 

34from pandas.core.arrays.arrow.dtype import ArrowDtype 

35from pandas.core.base import ( 

36 NoNewAttributesMixin, 

37 PandasObject, 

38) 

39from pandas.core.indexes.datetimes import DatetimeIndex 

40from pandas.core.indexes.timedeltas import TimedeltaIndex 

41 

42if TYPE_CHECKING: 

43 from pandas import ( 

44 DataFrame, 

45 Series, 

46 ) 

47 

48 

49class Properties(PandasDelegate, PandasObject, NoNewAttributesMixin): 

50 _hidden_attrs = PandasObject._hidden_attrs | { 

51 "orig", 

52 "name", 

53 } 

54 

55 def __init__(self, data: Series, orig) -> None: 

56 if not isinstance(data, ABCSeries): 

57 raise TypeError( 

58 f"cannot convert an object of type {type(data)} to a datetimelike index" 

59 ) 

60 

61 self._parent = data 

62 self.orig = orig 

63 self.name = getattr(data, "name", None) 

64 self._freeze() 

65 

66 def _get_values(self): 

67 data = self._parent 

68 if is_datetime64_dtype(data.dtype): 

69 return DatetimeIndex(data, copy=False, name=self.name) 

70 

71 elif is_datetime64tz_dtype(data.dtype): 

72 return DatetimeIndex(data, copy=False, name=self.name) 

73 

74 elif is_timedelta64_dtype(data.dtype): 

75 return TimedeltaIndex(data, copy=False, name=self.name) 

76 

77 elif is_period_dtype(data.dtype): 

78 return PeriodArray(data, copy=False) 

79 

80 raise TypeError( 

81 f"cannot convert an object of type {type(data)} to a datetimelike index" 

82 ) 

83 

84 def _delegate_property_get(self, name): 

85 from pandas import Series 

86 

87 values = self._get_values() 

88 

89 result = getattr(values, name) 

90 

91 # maybe need to upcast (ints) 

92 if isinstance(result, np.ndarray): 

93 if is_integer_dtype(result): 

94 result = result.astype("int64") 

95 elif not is_list_like(result): 

96 return result 

97 

98 result = np.asarray(result) 

99 

100 if self.orig is not None: 

101 index = self.orig.index 

102 else: 

103 index = self._parent.index 

104 # return the result as a Series 

105 result = Series(result, index=index, name=self.name).__finalize__(self._parent) 

106 

107 # setting this object will show a SettingWithCopyWarning/Error 

108 result._is_copy = ( 

109 "modifications to a property of a datetimelike " 

110 "object are not supported and are discarded. " 

111 "Change values on the original." 

112 ) 

113 

114 return result 

115 

116 def _delegate_property_set(self, name, value, *args, **kwargs): 

117 raise ValueError( 

118 "modifications to a property of a datetimelike object are not supported. " 

119 "Change values on the original." 

120 ) 

121 

122 def _delegate_method(self, name, *args, **kwargs): 

123 from pandas import Series 

124 

125 values = self._get_values() 

126 

127 method = getattr(values, name) 

128 result = method(*args, **kwargs) 

129 

130 if not is_list_like(result): 

131 return result 

132 

133 result = Series(result, index=self._parent.index, name=self.name).__finalize__( 

134 self._parent 

135 ) 

136 

137 # setting this object will show a SettingWithCopyWarning/Error 

138 result._is_copy = ( 

139 "modifications to a method of a datetimelike " 

140 "object are not supported and are discarded. " 

141 "Change values on the original." 

142 ) 

143 

144 return result 

145 

146 

147@delegate_names( 

148 delegate=ArrowExtensionArray, 

149 accessors=DatetimeArray._datetimelike_ops, 

150 typ="property", 

151 accessor_mapping=lambda x: f"_dt_{x}", 

152 raise_on_missing=False, 

153) 

154@delegate_names( 

155 delegate=ArrowExtensionArray, 

156 accessors=DatetimeArray._datetimelike_methods, 

157 typ="method", 

158 accessor_mapping=lambda x: f"_dt_{x}", 

159 raise_on_missing=False, 

160) 

161class ArrowTemporalProperties(PandasDelegate, PandasObject, NoNewAttributesMixin): 

162 def __init__(self, data: Series, orig) -> None: 

163 if not isinstance(data, ABCSeries): 

164 raise TypeError( 

165 f"cannot convert an object of type {type(data)} to a datetimelike index" 

166 ) 

167 

168 self._parent = data 

169 self._orig = orig 

170 self._freeze() 

171 

172 def _delegate_property_get(self, name: str): # type: ignore[override] 

173 if not hasattr(self._parent.array, f"_dt_{name}"): 

174 raise NotImplementedError( 

175 f"dt.{name} is not supported for {self._parent.dtype}" 

176 ) 

177 result = getattr(self._parent.array, f"_dt_{name}") 

178 

179 if not is_list_like(result): 

180 return result 

181 

182 if self._orig is not None: 

183 index = self._orig.index 

184 else: 

185 index = self._parent.index 

186 # return the result as a Series, which is by definition a copy 

187 result = type(self._parent)( 

188 result, index=index, name=self._parent.name 

189 ).__finalize__(self._parent) 

190 

191 return result 

192 

193 def _delegate_method(self, name: str, *args, **kwargs): 

194 if not hasattr(self._parent.array, f"_dt_{name}"): 

195 raise NotImplementedError( 

196 f"dt.{name} is not supported for {self._parent.dtype}" 

197 ) 

198 

199 result = getattr(self._parent.array, f"_dt_{name}")(*args, **kwargs) 

200 

201 if self._orig is not None: 

202 index = self._orig.index 

203 else: 

204 index = self._parent.index 

205 # return the result as a Series, which is by definition a copy 

206 result = type(self._parent)( 

207 result, index=index, name=self._parent.name 

208 ).__finalize__(self._parent) 

209 

210 return result 

211 

212 def to_pydatetime(self): 

213 return cast(ArrowExtensionArray, self._parent.array)._dt_to_pydatetime() 

214 

215 def isocalendar(self): 

216 from pandas import DataFrame 

217 

218 result = ( 

219 cast(ArrowExtensionArray, self._parent.array) 

220 ._dt_isocalendar() 

221 ._data.combine_chunks() 

222 ) 

223 iso_calendar_df = DataFrame( 

224 { 

225 col: type(self._parent.array)(result.field(i)) # type: ignore[call-arg] 

226 for i, col in enumerate(["year", "week", "day"]) 

227 } 

228 ) 

229 return iso_calendar_df 

230 

231 

232@delegate_names( 

233 delegate=DatetimeArray, 

234 accessors=DatetimeArray._datetimelike_ops + ["unit"], 

235 typ="property", 

236) 

237@delegate_names( 

238 delegate=DatetimeArray, 

239 accessors=DatetimeArray._datetimelike_methods + ["as_unit"], 

240 typ="method", 

241) 

242class DatetimeProperties(Properties): 

243 """ 

244 Accessor object for datetimelike properties of the Series values. 

245 

246 Examples 

247 -------- 

248 >>> seconds_series = pd.Series(pd.date_range("2000-01-01", periods=3, freq="s")) 

249 >>> seconds_series 

250 0 2000-01-01 00:00:00 

251 1 2000-01-01 00:00:01 

252 2 2000-01-01 00:00:02 

253 dtype: datetime64[ns] 

254 >>> seconds_series.dt.second 

255 0 0 

256 1 1 

257 2 2 

258 dtype: int32 

259 

260 >>> hours_series = pd.Series(pd.date_range("2000-01-01", periods=3, freq="h")) 

261 >>> hours_series 

262 0 2000-01-01 00:00:00 

263 1 2000-01-01 01:00:00 

264 2 2000-01-01 02:00:00 

265 dtype: datetime64[ns] 

266 >>> hours_series.dt.hour 

267 0 0 

268 1 1 

269 2 2 

270 dtype: int32 

271 

272 >>> quarters_series = pd.Series(pd.date_range("2000-01-01", periods=3, freq="q")) 

273 >>> quarters_series 

274 0 2000-03-31 

275 1 2000-06-30 

276 2 2000-09-30 

277 dtype: datetime64[ns] 

278 >>> quarters_series.dt.quarter 

279 0 1 

280 1 2 

281 2 3 

282 dtype: int32 

283 

284 Returns a Series indexed like the original Series. 

285 Raises TypeError if the Series does not contain datetimelike values. 

286 """ 

287 

288 def to_pydatetime(self) -> np.ndarray: 

289 """ 

290 Return the data as an array of :class:`datetime.datetime` objects. 

291 

292 Timezone information is retained if present. 

293 

294 .. warning:: 

295 

296 Python's datetime uses microsecond resolution, which is lower than 

297 pandas (nanosecond). The values are truncated. 

298 

299 Returns 

300 ------- 

301 numpy.ndarray 

302 Object dtype array containing native Python datetime objects. 

303 

304 See Also 

305 -------- 

306 datetime.datetime : Standard library value for a datetime. 

307 

308 Examples 

309 -------- 

310 >>> s = pd.Series(pd.date_range('20180310', periods=2)) 

311 >>> s 

312 0 2018-03-10 

313 1 2018-03-11 

314 dtype: datetime64[ns] 

315 

316 >>> s.dt.to_pydatetime() 

317 array([datetime.datetime(2018, 3, 10, 0, 0), 

318 datetime.datetime(2018, 3, 11, 0, 0)], dtype=object) 

319 

320 pandas' nanosecond precision is truncated to microseconds. 

321 

322 >>> s = pd.Series(pd.date_range('20180310', periods=2, freq='ns')) 

323 >>> s 

324 0 2018-03-10 00:00:00.000000000 

325 1 2018-03-10 00:00:00.000000001 

326 dtype: datetime64[ns] 

327 

328 >>> s.dt.to_pydatetime() 

329 array([datetime.datetime(2018, 3, 10, 0, 0), 

330 datetime.datetime(2018, 3, 10, 0, 0)], dtype=object) 

331 """ 

332 return self._get_values().to_pydatetime() 

333 

334 @property 

335 def freq(self): 

336 return self._get_values().inferred_freq 

337 

338 def isocalendar(self) -> DataFrame: 

339 """ 

340 Calculate year, week, and day according to the ISO 8601 standard. 

341 

342 .. versionadded:: 1.1.0 

343 

344 Returns 

345 ------- 

346 DataFrame 

347 With columns year, week and day. 

348 

349 See Also 

350 -------- 

351 Timestamp.isocalendar : Function return a 3-tuple containing ISO year, 

352 week number, and weekday for the given Timestamp object. 

353 datetime.date.isocalendar : Return a named tuple object with 

354 three components: year, week and weekday. 

355 

356 Examples 

357 -------- 

358 >>> ser = pd.to_datetime(pd.Series(["2010-01-01", pd.NaT])) 

359 >>> ser.dt.isocalendar() 

360 year week day 

361 0 2009 53 5 

362 1 <NA> <NA> <NA> 

363 >>> ser.dt.isocalendar().week 

364 0 53 

365 1 <NA> 

366 Name: week, dtype: UInt32 

367 """ 

368 return self._get_values().isocalendar().set_index(self._parent.index) 

369 

370 

371@delegate_names( 

372 delegate=TimedeltaArray, accessors=TimedeltaArray._datetimelike_ops, typ="property" 

373) 

374@delegate_names( 

375 delegate=TimedeltaArray, 

376 accessors=TimedeltaArray._datetimelike_methods, 

377 typ="method", 

378) 

379class TimedeltaProperties(Properties): 

380 """ 

381 Accessor object for datetimelike properties of the Series values. 

382 

383 Returns a Series indexed like the original Series. 

384 Raises TypeError if the Series does not contain datetimelike values. 

385 

386 Examples 

387 -------- 

388 >>> seconds_series = pd.Series( 

389 ... pd.timedelta_range(start="1 second", periods=3, freq="S") 

390 ... ) 

391 >>> seconds_series 

392 0 0 days 00:00:01 

393 1 0 days 00:00:02 

394 2 0 days 00:00:03 

395 dtype: timedelta64[ns] 

396 >>> seconds_series.dt.seconds 

397 0 1 

398 1 2 

399 2 3 

400 dtype: int32 

401 """ 

402 

403 def to_pytimedelta(self) -> np.ndarray: 

404 """ 

405 Return an array of native :class:`datetime.timedelta` objects. 

406 

407 Python's standard `datetime` library uses a different representation 

408 timedelta's. This method converts a Series of pandas Timedeltas 

409 to `datetime.timedelta` format with the same length as the original 

410 Series. 

411 

412 Returns 

413 ------- 

414 numpy.ndarray 

415 Array of 1D containing data with `datetime.timedelta` type. 

416 

417 See Also 

418 -------- 

419 datetime.timedelta : A duration expressing the difference 

420 between two date, time, or datetime. 

421 

422 Examples 

423 -------- 

424 >>> s = pd.Series(pd.to_timedelta(np.arange(5), unit="d")) 

425 >>> s 

426 0 0 days 

427 1 1 days 

428 2 2 days 

429 3 3 days 

430 4 4 days 

431 dtype: timedelta64[ns] 

432 

433 >>> s.dt.to_pytimedelta() 

434 array([datetime.timedelta(0), datetime.timedelta(days=1), 

435 datetime.timedelta(days=2), datetime.timedelta(days=3), 

436 datetime.timedelta(days=4)], dtype=object) 

437 """ 

438 return self._get_values().to_pytimedelta() 

439 

440 @property 

441 def components(self): 

442 """ 

443 Return a Dataframe of the components of the Timedeltas. 

444 

445 Returns 

446 ------- 

447 DataFrame 

448 

449 Examples 

450 -------- 

451 >>> s = pd.Series(pd.to_timedelta(np.arange(5), unit='s')) 

452 >>> s 

453 0 0 days 00:00:00 

454 1 0 days 00:00:01 

455 2 0 days 00:00:02 

456 3 0 days 00:00:03 

457 4 0 days 00:00:04 

458 dtype: timedelta64[ns] 

459 >>> s.dt.components 

460 days hours minutes seconds milliseconds microseconds nanoseconds 

461 0 0 0 0 0 0 0 0 

462 1 0 0 0 1 0 0 0 

463 2 0 0 0 2 0 0 0 

464 3 0 0 0 3 0 0 0 

465 4 0 0 0 4 0 0 0 

466 """ 

467 return ( 

468 self._get_values() 

469 .components.set_index(self._parent.index) 

470 .__finalize__(self._parent) 

471 ) 

472 

473 @property 

474 def freq(self): 

475 return self._get_values().inferred_freq 

476 

477 

478@delegate_names( 

479 delegate=PeriodArray, accessors=PeriodArray._datetimelike_ops, typ="property" 

480) 

481@delegate_names( 

482 delegate=PeriodArray, accessors=PeriodArray._datetimelike_methods, typ="method" 

483) 

484class PeriodProperties(Properties): 

485 """ 

486 Accessor object for datetimelike properties of the Series values. 

487 

488 Returns a Series indexed like the original Series. 

489 Raises TypeError if the Series does not contain datetimelike values. 

490 

491 Examples 

492 -------- 

493 >>> seconds_series = pd.Series( 

494 ... pd.period_range( 

495 ... start="2000-01-01 00:00:00", end="2000-01-01 00:00:03", freq="s" 

496 ... ) 

497 ... ) 

498 >>> seconds_series 

499 0 2000-01-01 00:00:00 

500 1 2000-01-01 00:00:01 

501 2 2000-01-01 00:00:02 

502 3 2000-01-01 00:00:03 

503 dtype: period[S] 

504 >>> seconds_series.dt.second 

505 0 0 

506 1 1 

507 2 2 

508 3 3 

509 dtype: int64 

510 

511 >>> hours_series = pd.Series( 

512 ... pd.period_range(start="2000-01-01 00:00", end="2000-01-01 03:00", freq="h") 

513 ... ) 

514 >>> hours_series 

515 0 2000-01-01 00:00 

516 1 2000-01-01 01:00 

517 2 2000-01-01 02:00 

518 3 2000-01-01 03:00 

519 dtype: period[H] 

520 >>> hours_series.dt.hour 

521 0 0 

522 1 1 

523 2 2 

524 3 3 

525 dtype: int64 

526 

527 >>> quarters_series = pd.Series( 

528 ... pd.period_range(start="2000-01-01", end="2000-12-31", freq="Q-DEC") 

529 ... ) 

530 >>> quarters_series 

531 0 2000Q1 

532 1 2000Q2 

533 2 2000Q3 

534 3 2000Q4 

535 dtype: period[Q-DEC] 

536 >>> quarters_series.dt.quarter 

537 0 1 

538 1 2 

539 2 3 

540 3 4 

541 dtype: int64 

542 """ 

543 

544 

545class CombinedDatetimelikeProperties( 

546 DatetimeProperties, TimedeltaProperties, PeriodProperties 

547): 

548 def __new__(cls, data: Series): 

549 # CombinedDatetimelikeProperties isn't really instantiated. Instead 

550 # we need to choose which parent (datetime or timedelta) is 

551 # appropriate. Since we're checking the dtypes anyway, we'll just 

552 # do all the validation here. 

553 

554 if not isinstance(data, ABCSeries): 

555 raise TypeError( 

556 f"cannot convert an object of type {type(data)} to a datetimelike index" 

557 ) 

558 

559 orig = data if is_categorical_dtype(data.dtype) else None 

560 if orig is not None: 

561 data = data._constructor( 

562 orig.array, 

563 name=orig.name, 

564 copy=False, 

565 dtype=orig._values.categories.dtype, 

566 index=orig.index, 

567 ) 

568 

569 if isinstance(data.dtype, ArrowDtype) and data.dtype.kind == "M": 

570 return ArrowTemporalProperties(data, orig) 

571 if is_datetime64_dtype(data.dtype): 

572 return DatetimeProperties(data, orig) 

573 elif is_datetime64tz_dtype(data.dtype): 

574 return DatetimeProperties(data, orig) 

575 elif is_timedelta64_dtype(data.dtype): 

576 return TimedeltaProperties(data, orig) 

577 elif is_period_dtype(data.dtype): 

578 return PeriodProperties(data, orig) 

579 

580 raise AttributeError("Can only use .dt accessor with datetimelike values")