Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pandas/core/indexes/datetimes.py: 27%

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

508 statements  

1from __future__ import annotations 

2 

3import datetime as dt 

4import operator 

5from typing import ( 

6 TYPE_CHECKING, 

7 Self, 

8) 

9import warnings 

10 

11import numpy as np 

12 

13from pandas._libs import ( 

14 NaT, 

15 Period, 

16 Timestamp, 

17 index as libindex, 

18 lib, 

19) 

20from pandas._libs.tslibs import ( 

21 Resolution, 

22 Tick, 

23 Timedelta, 

24 periods_per_day, 

25 timezones, 

26 to_offset, 

27) 

28from pandas._libs.tslibs.dtypes import abbrev_to_npy_unit 

29from pandas._libs.tslibs.offsets import ( 

30 DateOffset, 

31 prefix_mapping, 

32) 

33from pandas.errors import Pandas4Warning 

34from pandas.util._decorators import ( 

35 cache_readonly, 

36 set_module, 

37) 

38from pandas.util._exceptions import find_stack_level 

39 

40from pandas.core.dtypes.common import is_scalar 

41from pandas.core.dtypes.dtypes import ( 

42 ArrowDtype, 

43 DatetimeTZDtype, 

44) 

45from pandas.core.dtypes.generic import ABCSeries 

46from pandas.core.dtypes.missing import is_valid_na_for_dtype 

47 

48from pandas.core.arrays.datetimes import ( 

49 DatetimeArray, 

50 tz_to_dtype, 

51) 

52import pandas.core.common as com 

53from pandas.core.indexes.base import ( 

54 Index, 

55 maybe_extract_name, 

56) 

57from pandas.core.indexes.datetimelike import DatetimeTimedeltaMixin 

58from pandas.core.tools.times import to_time 

59 

60if TYPE_CHECKING: 

61 from collections.abc import Hashable 

62 

63 from pandas._typing import ( 

64 Dtype, 

65 DtypeObj, 

66 Frequency, 

67 IntervalClosedType, 

68 TimeAmbiguous, 

69 TimeNonexistent, 

70 TimeUnit, 

71 npt, 

72 ) 

73 from pandas.core.api import ( 

74 DataFrame, 

75 PeriodIndex, 

76 ) 

77 

78from pandas._libs.tslibs.dtypes import OFFSET_TO_PERIOD_FREQSTR 

79 

80 

81def _new_DatetimeIndex(cls, d): 

82 """ 

83 This is called upon unpickling, rather than the default which doesn't 

84 have arguments and breaks __new__ 

85 """ 

86 if "data" in d and not isinstance(d["data"], DatetimeIndex): 

87 # Avoid need to verify integrity by calling simple_new directly 

88 data = d.pop("data") 

89 if not isinstance(data, DatetimeArray): 

90 # For backward compat with older pickles, we may need to construct 

91 # a DatetimeArray to adapt to the newer _simple_new signature 

92 tz = d.pop("tz") 

93 freq = d.pop("freq") 

94 dta = DatetimeArray._simple_new(data, dtype=tz_to_dtype(tz)) 

95 else: 

96 dta = data 

97 if "tz" in d: 

98 assert d.pop("tz") == dta.tz 

99 # Legacy pickles stored freq on the DatetimeArray; current pickles 

100 # include it in ``d``. Migrate either up onto the Index. 

101 legacy_freq = vars(dta).pop("_freq", None) 

102 freq = d.pop("freq", legacy_freq) 

103 result = cls._simple_new(dta, **d) 

104 result._freq = freq 

105 else: 

106 with warnings.catch_warnings(): 

107 # TODO: If we knew what was going in to **d, we might be able to 

108 # go through _simple_new instead 

109 warnings.simplefilter("ignore") 

110 result = cls.__new__(cls, **d) 

111 

112 return result 

113 

114 

115@set_module("pandas") 

116class DatetimeIndex(DatetimeTimedeltaMixin): 

117 """ 

118 Immutable ndarray-like of datetime64 data. 

119 

120 Represented internally as int64, and which can be boxed to Timestamp objects 

121 that are subclasses of datetime and carry metadata. 

122 

123 .. versionchanged:: 2.0.0 

124 The various numeric date/time attributes (:attr:`~DatetimeIndex.day`, 

125 :attr:`~DatetimeIndex.month`, :attr:`~DatetimeIndex.year` etc.) now have dtype 

126 ``int32``. Previously they had dtype ``int64``. 

127 

128 Parameters 

129 ---------- 

130 data : array-like (1-dimensional) 

131 Datetime-like data to construct index with. 

132 freq : str or pandas offset object, optional 

133 One of pandas date offset strings or corresponding objects. The string 

134 'infer' can be passed in order to set the frequency of the index as the 

135 inferred frequency upon creation. 

136 tz : zoneinfo.ZoneInfo, pytz.timezone, dateutil.tz.tzfile, datetime.tzinfo or str 

137 Set the Timezone of the data. 

138 ambiguous : 'infer', bool-ndarray, 'NaT', default 'raise' 

139 When clocks moved backward due to DST, ambiguous times may arise. 

140 For example in Central European Time (UTC+01), when going from 03:00 

141 DST to 02:00 non-DST, 02:30:00 local time occurs both at 00:30:00 UTC 

142 and at 01:30:00 UTC. In such a situation, the `ambiguous` parameter 

143 dictates how ambiguous times should be handled. 

144 

145 - 'infer' will attempt to infer fall dst-transition hours based on 

146 order. Requires that the timestamps are monotonically increasing. 

147 - bool-ndarray where True signifies a DST time, False signifies a 

148 non-DST time (note that this flag is only applicable for ambiguous 

149 times) 

150 - 'NaT' will return NaT where there are ambiguous times 

151 - 'raise' will raise a ValueError if there are ambiguous times. 

152 

153 .. deprecated:: 3.1.0 

154 Use :meth:`DatetimeIndex.tz_localize` instead. 

155 dayfirst : bool, default False 

156 If True, parse dates in `data` with the day first order. 

157 

158 .. deprecated:: 3.1.0 

159 Use :func:`to_datetime` instead. 

160 yearfirst : bool, default False 

161 If True parse dates in `data` with the year first order. 

162 

163 .. deprecated:: 3.1.0 

164 Use :func:`to_datetime` instead. 

165 dtype : numpy.dtype or DatetimeTZDtype or str, default None 

166 Note that the only NumPy dtypes allowed are 'datetime64[ns]', 

167 'datetime64[us]', 'datetime64[ms]', 'datetime64[s]'. 

168 copy : bool, default None 

169 Whether to copy input data, only relevant for array, Series, and Index 

170 inputs (for other input, e.g. a list, a new array is created anyway). 

171 Defaults to True for array input and False for Index/Series. 

172 Set to False to avoid copying array input at your own risk (if you 

173 know the input data won't be modified elsewhere). 

174 Set to True to force copying Series/Index up front. 

175 name : label, default None 

176 Name to be stored in the index. 

177 

178 Attributes 

179 ---------- 

180 year 

181 month 

182 day 

183 hour 

184 minute 

185 second 

186 microsecond 

187 nanosecond 

188 date 

189 time 

190 timetz 

191 dayofyear 

192 day_of_year 

193 dayofweek 

194 day_of_week 

195 weekday 

196 quarter 

197 tz 

198 freq 

199 freqstr 

200 is_month_start 

201 is_month_end 

202 is_quarter_start 

203 is_quarter_end 

204 is_year_start 

205 is_year_end 

206 is_leap_year 

207 inferred_freq 

208 

209 Methods 

210 ------- 

211 normalize 

212 strftime 

213 snap 

214 tz_convert 

215 tz_localize 

216 round 

217 floor 

218 ceil 

219 to_period 

220 to_pydatetime 

221 to_series 

222 to_frame 

223 to_julian_date 

224 month_name 

225 day_name 

226 mean 

227 std 

228 

229 See Also 

230 -------- 

231 Index : The base pandas Index type. 

232 TimedeltaIndex : Index of timedelta64 data. 

233 PeriodIndex : Index of Period data. 

234 to_datetime : Convert argument to datetime. 

235 date_range : Create a fixed-frequency DatetimeIndex. 

236 

237 Notes 

238 ----- 

239 To learn more about the frequency strings, please see 

240 :ref:`this link<timeseries.offset_aliases>`. 

241 

242 Examples 

243 -------- 

244 >>> idx = pd.DatetimeIndex(["1/1/2020 10:00:00+00:00", "2/1/2020 11:00:00+00:00"]) 

245 >>> idx 

246 DatetimeIndex(['2020-01-01 10:00:00+00:00', '2020-02-01 11:00:00+00:00'], 

247 dtype='datetime64[us, UTC]', freq=None) 

248 """ 

249 

250 _typ = "datetimeindex" 

251 

252 _data_cls = DatetimeArray 

253 _supports_partial_string_indexing = True 

254 

255 @property 

256 def _engine_type(self) -> type[libindex.DatetimeEngine]: 

257 return libindex.DatetimeEngine 

258 

259 _data: DatetimeArray 

260 _values: DatetimeArray 

261 

262 # -------------------------------------------------------------------- 

263 # properties dispatching to DatetimeArray without wrapping the result 

264 

265 @property 

266 def tz(self) -> dt.tzinfo | None: 

267 """ 

268 Return the timezone. 

269 

270 This property returns the timezone information associated with the 

271 DatetimeIndex. If the data is timezone-naive (i.e. has no timezone 

272 information), it returns None. 

273 

274 Returns 

275 ------- 

276 zoneinfo.ZoneInfo, datetime.tzinfo, pytz.tzinfo.BaseTZInfo, dateutil.tz.tz.tzfile, or None 

277 Returns None when the DatetimeIndex is tz-naive. 

278 

279 See Also 

280 -------- 

281 DatetimeIndex.tz_localize : Localize tz-naive DatetimeIndex to a 

282 given time zone, or remove timezone from a tz-aware DatetimeIndex. 

283 DatetimeIndex.tz_convert : Convert tz-aware DatetimeIndex from 

284 one time zone to another. 

285 

286 Examples 

287 -------- 

288 >>> idx = pd.DatetimeIndex( 

289 ... ["1/1/2020 10:00:00+00:00", "2/1/2020 11:00:00+00:00"] 

290 ... ) 

291 >>> idx.tz 

292 datetime.timezone.utc 

293 """ # noqa: E501 

294 return self._data.tz 

295 

296 @tz.setter 

297 def tz(self, value) -> None: 

298 # GH#3746 disallow localizing or converting via attribute assignment; 

299 # delegate to DatetimeArray.tz for the raised error message 

300 self._data.tz = value 

301 

302 @property 

303 def tzinfo(self) -> dt.tzinfo | None: 

304 """ 

305 Alias for tz attribute. 

306 

307 Examples 

308 -------- 

309 >>> idx = pd.DatetimeIndex( 

310 ... ["1/1/2020 10:00:00+00:00", "2/1/2020 11:00:00+00:00"] 

311 ... ) 

312 >>> idx.tzinfo 

313 datetime.timezone.utc 

314 """ 

315 return self.tz 

316 

317 @cache_readonly 

318 def is_normalized(self) -> bool: 

319 """ 

320 Returns True if all of the dates are at midnight ("no time"). 

321 

322 Examples 

323 -------- 

324 >>> idx = pd.DatetimeIndex(["2020-01-01 00:00:00", "2020-02-01 00:00:00"]) 

325 >>> idx.is_normalized 

326 True 

327 

328 >>> idx = pd.DatetimeIndex(["2020-01-01 00:00:01", "2020-02-01 00:00:00"]) 

329 >>> idx.is_normalized 

330 False 

331 """ 

332 return self._data.is_normalized 

333 

334 # field_ops: wrap result in Index 

335 

336 def _wrap_field(self, name: str) -> Index: 

337 result = getattr(self._data, name) 

338 return Index(result, name=self.name, dtype=result.dtype, copy=False) 

339 

340 @property 

341 def year(self) -> Index: 

342 """ 

343 The year of the datetime. 

344 

345 This attribute returns the year component of each datetime value 

346 in the DatetimeIndex. 

347 

348 See Also 

349 -------- 

350 DatetimeIndex.month: The month as January=1, December=12. 

351 DatetimeIndex.day: The day of the datetime. 

352 

353 Examples 

354 -------- 

355 >>> idx = pd.DatetimeIndex(["2000-12-31", "2001-12-31", "2002-12-31"]) 

356 >>> idx.year 

357 Index([2000, 2001, 2002], dtype='int32') 

358 """ 

359 return self._wrap_field("year") 

360 

361 @property 

362 def month(self) -> Index: 

363 """ 

364 The month as January=1, December=12. 

365 

366 This attribute returns the month component of each datetime value 

367 in the DatetimeIndex. 

368 

369 See Also 

370 -------- 

371 DatetimeIndex.year: The year of the datetime. 

372 DatetimeIndex.day: The day of the datetime. 

373 

374 Examples 

375 -------- 

376 >>> idx = pd.DatetimeIndex(["2000-01-31", "2000-02-29", "2000-03-31"]) 

377 >>> idx.month 

378 Index([1, 2, 3], dtype='int32') 

379 """ 

380 return self._wrap_field("month") 

381 

382 @property 

383 def day(self) -> Index: 

384 """ 

385 The day of the datetime. 

386 

387 This attribute returns the day of the month component of each 

388 datetime value in the DatetimeIndex. 

389 

390 See Also 

391 -------- 

392 DatetimeIndex.year: The year of the datetime. 

393 DatetimeIndex.month: The month as January=1, December=12. 

394 DatetimeIndex.hour: The hours of the datetime. 

395 

396 Examples 

397 -------- 

398 >>> idx = pd.DatetimeIndex(["2000-01-01", "2000-01-02", "2000-01-03"]) 

399 >>> idx.day 

400 Index([1, 2, 3], dtype='int32') 

401 """ 

402 return self._wrap_field("day") 

403 

404 @property 

405 def hour(self) -> Index: 

406 """ 

407 The hours of the datetime. 

408 

409 This attribute returns the hour component of each datetime value 

410 in the DatetimeIndex. 

411 

412 See Also 

413 -------- 

414 DatetimeIndex.day: The day of the datetime. 

415 DatetimeIndex.minute: The minutes of the datetime. 

416 DatetimeIndex.second: The seconds of the datetime. 

417 

418 Examples 

419 -------- 

420 >>> idx = pd.date_range("2000-01-01", periods=3, freq="h") 

421 >>> idx.hour 

422 Index([0, 1, 2], dtype='int32') 

423 """ 

424 return self._wrap_field("hour") 

425 

426 @property 

427 def minute(self) -> Index: 

428 """ 

429 The minutes of the datetime. 

430 

431 This attribute returns the minute component of each datetime value 

432 in the DatetimeIndex. 

433 

434 See Also 

435 -------- 

436 DatetimeIndex.hour: The hours of the datetime. 

437 DatetimeIndex.second: The seconds of the datetime. 

438 

439 Examples 

440 -------- 

441 >>> idx = pd.date_range("2000-01-01", periods=3, freq="min") 

442 >>> idx.minute 

443 Index([0, 1, 2], dtype='int32') 

444 """ 

445 return self._wrap_field("minute") 

446 

447 @property 

448 def second(self) -> Index: 

449 """ 

450 The seconds of the datetime. 

451 

452 This attribute returns the second component of each datetime value 

453 in the DatetimeIndex. 

454 

455 See Also 

456 -------- 

457 DatetimeIndex.minute: The minutes of the datetime. 

458 DatetimeIndex.microsecond: The microseconds of the datetime. 

459 DatetimeIndex.nanosecond: The nanoseconds of the datetime. 

460 

461 Examples 

462 -------- 

463 >>> idx = pd.date_range("2000-01-01", periods=3, freq="s") 

464 >>> idx.second 

465 Index([0, 1, 2], dtype='int32') 

466 """ 

467 return self._wrap_field("second") 

468 

469 @property 

470 def weekday(self) -> Index: 

471 """ 

472 The day of the week with Monday=0, Sunday=6. 

473 

474 .. deprecated:: 3.1.0 

475 Use :attr:`DatetimeIndex.day_of_week` instead. 

476 """ 

477 # GH#12816 

478 warnings.warn( 

479 "DatetimeIndex.weekday is deprecated and will be removed " 

480 "in a future version. Use DatetimeIndex.day_of_week instead.", 

481 Pandas4Warning, 

482 stacklevel=find_stack_level(), 

483 ) 

484 return self._wrap_field("day_of_week") 

485 

486 @property 

487 def dayofweek(self) -> Index: 

488 """ 

489 The day of the week with Monday=0, Sunday=6. 

490 

491 .. deprecated:: 3.1.0 

492 Use :attr:`DatetimeIndex.day_of_week` instead. 

493 """ 

494 warnings.warn( 

495 "DatetimeIndex.dayofweek is deprecated and will be removed in a " 

496 "future version. Use DatetimeIndex.day_of_week instead.", 

497 Pandas4Warning, 

498 stacklevel=find_stack_level(), 

499 ) 

500 return self._wrap_field("day_of_week") 

501 

502 @property 

503 def day_of_week(self) -> Index: 

504 """ 

505 The day of the week with Monday=0, Sunday=6. 

506 

507 Return the day of the week. It is assumed the week starts on 

508 Monday, which is denoted by 0 and ends on Sunday which is denoted 

509 by 6. 

510 

511 See Also 

512 -------- 

513 DatetimeIndex.day_of_year : The ordinal day of the year. 

514 DatetimeIndex.day_name : Return the name of the day of the week. 

515 

516 Examples 

517 -------- 

518 >>> idx = pd.DatetimeIndex(["2016-12-31", "2017-01-01", "2017-01-02"]) 

519 >>> idx.day_of_week 

520 Index([5, 6, 0], dtype='int32') 

521 """ 

522 return self._wrap_field("day_of_week") 

523 

524 @property 

525 def dayofyear(self) -> Index: 

526 """ 

527 The ordinal day of the year. 

528 

529 .. deprecated:: 3.1.0 

530 Use :attr:`DatetimeIndex.day_of_year` instead. 

531 """ 

532 warnings.warn( 

533 "DatetimeIndex.dayofyear is deprecated and will be removed in a " 

534 "future version. Use DatetimeIndex.day_of_year instead.", 

535 Pandas4Warning, 

536 stacklevel=find_stack_level(), 

537 ) 

538 return self._wrap_field("day_of_year") 

539 

540 @property 

541 def day_of_year(self) -> Index: 

542 """ 

543 The ordinal day of the year. 

544 

545 This attribute returns the day of the year for each datetime value 

546 in the DatetimeIndex. Values range from 1 to 365 (or 366 for leap 

547 years). 

548 

549 See Also 

550 -------- 

551 DatetimeIndex.day_of_week : The day of the week with Monday=0, Sunday=6. 

552 DatetimeIndex.day : The day of the datetime. 

553 

554 Examples 

555 -------- 

556 >>> idx = pd.DatetimeIndex(["2020-01-01", "2020-02-01"]) 

557 >>> idx.day_of_year 

558 Index([1, 32], dtype='int32') 

559 """ 

560 return self._wrap_field("day_of_year") 

561 

562 @property 

563 def quarter(self) -> Index: 

564 """ 

565 The quarter of the date. 

566 

567 This attribute returns the quarter of the year for each datetime 

568 value in the DatetimeIndex. Quarter 1 includes January through 

569 March, quarter 2 includes April through June, quarter 3 includes 

570 July through September, and quarter 4 includes October through 

571 December. 

572 

573 See Also 

574 -------- 

575 DatetimeIndex.month : The month as January=1, December=12. 

576 DatetimeIndex.is_quarter_start : Indicator for whether the date is the 

577 first day of a quarter. 

578 DatetimeIndex.is_quarter_end : Indicator for whether the date is the 

579 last day of a quarter. 

580 

581 Examples 

582 -------- 

583 >>> idx = pd.DatetimeIndex(["2020-01-01", "2020-04-01"]) 

584 >>> idx.quarter 

585 Index([1, 2], dtype='int32') 

586 """ 

587 return self._wrap_field("quarter") 

588 

589 @property 

590 def days_in_month(self) -> Index: 

591 """ 

592 The number of days in the month. 

593 

594 This attribute returns the total number of days in the month for 

595 each datetime value in the DatetimeIndex. The value depends on the 

596 month and whether the year is a leap year (e.g., February has 29 

597 days in a leap year). 

598 

599 See Also 

600 -------- 

601 DatetimeIndex.day : Return the day of the month. 

602 DatetimeIndex.is_month_end : Return a boolean indicating if the 

603 date is the last day of the month. 

604 DatetimeIndex.is_month_start : Return a boolean indicating if the 

605 date is the first day of the month. 

606 DatetimeIndex.month : Return the month as January=1 through 

607 December=12. 

608 

609 Examples 

610 -------- 

611 >>> idx = pd.DatetimeIndex(["2020-01-01", "2020-02-01"]) 

612 >>> idx.days_in_month 

613 Index([31, 29], dtype='int32') 

614 """ 

615 return self._wrap_field("days_in_month") 

616 

617 @property 

618 def daysinmonth(self) -> Index: 

619 """ 

620 The number of days in the month. 

621 

622 .. deprecated:: 3.1.0 

623 Use :attr:`DatetimeIndex.days_in_month` instead. 

624 """ 

625 warnings.warn( 

626 "DatetimeIndex.daysinmonth is deprecated and will be removed in a " 

627 "future version. Use DatetimeIndex.days_in_month instead.", 

628 Pandas4Warning, 

629 stacklevel=find_stack_level(), 

630 ) 

631 return self._wrap_field("days_in_month") 

632 

633 @property 

634 def microsecond(self) -> Index: 

635 """ 

636 The microseconds of the datetime. 

637 

638 This attribute returns the microsecond component of each datetime 

639 value in the DatetimeIndex. Values range from 0 to 999999 (one 

640 microsecond is one millionth of a second). 

641 

642 See Also 

643 -------- 

644 DatetimeIndex.second: The seconds of the datetime. 

645 DatetimeIndex.nanosecond: The nanoseconds of the datetime. 

646 

647 Examples 

648 -------- 

649 >>> idx = pd.date_range("2000-01-01", periods=3, freq="us") 

650 >>> idx.microsecond 

651 Index([0, 1, 2], dtype='int32') 

652 """ 

653 return self._wrap_field("microsecond") 

654 

655 @property 

656 def nanosecond(self) -> Index: 

657 """ 

658 The nanoseconds of the datetime. 

659 

660 This attribute returns the nanosecond component of each datetime 

661 value in the DatetimeIndex. Values range from 0 to 999 (one 

662 nanosecond is one billionth of a second). 

663 

664 See Also 

665 -------- 

666 DatetimeIndex.second: The seconds of the datetime. 

667 DatetimeIndex.microsecond: The microseconds of the datetime. 

668 

669 Examples 

670 -------- 

671 >>> idx = pd.date_range("2000-01-01", periods=3, freq="ns") 

672 >>> idx.nanosecond 

673 Index([0, 1, 2], dtype='int32') 

674 """ 

675 return self._wrap_field("nanosecond") 

676 

677 # bool_ops: return raw result 

678 

679 @property 

680 def is_month_start(self) -> npt.NDArray[np.bool_]: 

681 """ 

682 Indicates whether the date is the first day of the month. 

683 

684 This boolean attribute evaluates to True if the date falls on the 

685 first day of a calendar month, and False otherwise. 

686 If the index has a business ``freq`` (e.g. ``"BMS"``), the result 

687 follows that frequency's month boundaries instead of the calendar's. 

688 

689 See Also 

690 -------- 

691 DatetimeIndex.is_month_end : Return a boolean indicating whether the 

692 date is the last day of the month. 

693 

694 Examples 

695 -------- 

696 >>> idx = pd.date_range("2018-02-27", periods=3) 

697 >>> idx.is_month_start 

698 array([False, False, True]) 

699 """ 

700 return self._data._get_start_end_field("is_month_start", self.freq) 

701 

702 @property 

703 def is_month_end(self) -> npt.NDArray[np.bool_]: 

704 """ 

705 Indicates whether the date is the last day of the month. 

706 

707 This boolean attribute evaluates to True if the date falls on the 

708 last day of a calendar month, and False otherwise. 

709 If the index has a business ``freq`` (e.g. ``"BME"``), the result 

710 follows that frequency's month boundaries instead of the calendar's. 

711 

712 See Also 

713 -------- 

714 DatetimeIndex.is_month_start : Return a boolean indicating whether 

715 the date is the first day of the month. 

716 

717 Examples 

718 -------- 

719 >>> idx = pd.date_range("2018-02-27", periods=3) 

720 >>> idx.is_month_end 

721 array([False, True, False]) 

722 """ 

723 return self._data._get_start_end_field("is_month_end", self.freq) 

724 

725 @property 

726 def is_quarter_start(self) -> npt.NDArray[np.bool_]: 

727 """ 

728 Indicator for whether the date is the first day of a quarter. 

729 

730 This boolean attribute evaluates to True if the date falls on the 

731 first day of a calendar quarter (January 1, April 1, July 1, or 

732 October 1), and False otherwise. 

733 If the index has a business or anchored ``freq`` (e.g. ``"BQS"`` or 

734 ``"QS-FEB"``), the result follows that frequency's quarter boundaries 

735 instead of the calendar's. 

736 

737 See Also 

738 -------- 

739 DatetimeIndex.quarter : Return the quarter of the date. 

740 DatetimeIndex.is_quarter_end : Similar property for indicating the 

741 quarter end. 

742 

743 Examples 

744 -------- 

745 >>> idx = pd.date_range("2017-03-30", periods=4) 

746 >>> idx.is_quarter_start 

747 array([False, False, True, False]) 

748 """ 

749 return self._data._get_start_end_field("is_quarter_start", self.freq) 

750 

751 @property 

752 def is_quarter_end(self) -> npt.NDArray[np.bool_]: 

753 """ 

754 Indicator for whether the date is the last day of a quarter. 

755 

756 This boolean attribute evaluates to True if the date falls on the 

757 last day of a calendar quarter (March 31, June 30, September 30, or 

758 December 31), and False otherwise. 

759 If the index has a business or anchored ``freq`` (e.g. ``"BQE"`` or 

760 ``"QE-NOV"``), the result follows that frequency's quarter boundaries 

761 instead of the calendar's. 

762 

763 See Also 

764 -------- 

765 DatetimeIndex.quarter : Return the quarter of the date. 

766 DatetimeIndex.is_quarter_start : Similar property indicating the 

767 quarter start. 

768 

769 Examples 

770 -------- 

771 >>> idx = pd.date_range("2017-03-30", periods=4) 

772 >>> idx.is_quarter_end 

773 array([False, True, False, False]) 

774 """ 

775 return self._data._get_start_end_field("is_quarter_end", self.freq) 

776 

777 @property 

778 def is_year_start(self) -> npt.NDArray[np.bool_]: 

779 """ 

780 Indicate whether the date is the first day of a year. 

781 

782 This boolean attribute evaluates to True if the date is January 1st, 

783 and False otherwise. 

784 If the index has a business or anchored ``freq`` (e.g. ``"BYS"`` or 

785 ``"YS-APR"``), the result follows that frequency's year boundaries 

786 instead of the calendar's. 

787 

788 See Also 

789 -------- 

790 DatetimeIndex.is_year_end : Similar property indicating the last day 

791 of the year. 

792 

793 Examples 

794 -------- 

795 >>> idx = pd.date_range("2017-12-30", periods=3) 

796 >>> idx.is_year_start 

797 array([False, False, True]) 

798 

799 With a business ``freq``, the first business day of the year counts 

800 as the year start even when it is not January 1st: 

801 

802 >>> idx = pd.date_range("2020-10-30", periods=4, freq="BYS") 

803 >>> idx 

804 DatetimeIndex(['2021-01-01', '2022-01-03', '2023-01-02', '2024-01-01'], 

805 dtype='datetime64[us]', freq='BYS-JAN') 

806 >>> idx.is_year_start 

807 array([ True, True, True, True]) 

808 """ 

809 return self._data._get_start_end_field("is_year_start", self.freq) 

810 

811 @property 

812 def is_year_end(self) -> npt.NDArray[np.bool_]: 

813 """ 

814 Indicate whether the date is the last day of the year. 

815 

816 This boolean attribute evaluates to True if the date is December 

817 31st, and False otherwise. 

818 If the index has a business or anchored ``freq`` (e.g. ``"BYE"`` or 

819 ``"YE-MAR"``), the result follows that frequency's year boundaries 

820 instead of the calendar's. 

821 

822 See Also 

823 -------- 

824 DatetimeIndex.is_year_start : Similar property indicating the start 

825 of the year. 

826 

827 Examples 

828 -------- 

829 >>> idx = pd.date_range("2017-12-30", periods=3) 

830 >>> idx.is_year_end 

831 array([False, True, False]) 

832 """ 

833 return self._data._get_start_end_field("is_year_end", self.freq) 

834 

835 @property 

836 def is_leap_year(self) -> npt.NDArray[np.bool_]: 

837 """ 

838 Boolean indicator if the date belongs to a leap year. 

839 

840 A leap year is a year, which has 366 days (instead of 365) including 

841 29th of February as an intercalary day. Leap years are years which 

842 are multiples of four with the exception of years divisible by 100 

843 but not by 400. 

844 

845 See Also 

846 -------- 

847 DatetimeIndex.is_year_end : Indicate whether the date is the last 

848 day of the year. 

849 DatetimeIndex.is_year_start : Indicate whether the date is the first 

850 day of a year. 

851 

852 Examples 

853 -------- 

854 >>> idx = pd.date_range("2012-01-01", "2015-01-01", freq="YE") 

855 >>> idx.is_leap_year 

856 array([ True, False, False]) 

857 """ 

858 return self._data.is_leap_year 

859 

860 # -------------------------------------------------------------------- 

861 # properties and methods dispatching to DatetimeArray, result not wrapped 

862 

863 @property 

864 def date(self) -> npt.NDArray[np.object_]: 

865 """ 

866 Returns numpy array of python :class:`datetime.date` objects. 

867 

868 Namely, the date part of Timestamps without time and 

869 timezone information. 

870 

871 See Also 

872 -------- 

873 DatetimeIndex.time : Returns numpy array of :class:`datetime.time` objects. 

874 The time part of the Timestamps. 

875 DatetimeIndex.year : The year of the datetime. 

876 DatetimeIndex.month : The month as January=1, December=12. 

877 DatetimeIndex.day : The day of the datetime. 

878 

879 Examples 

880 -------- 

881 >>> idx = pd.DatetimeIndex( 

882 ... ["1/1/2020 10:00:00+00:00", "2/1/2020 11:00:00+00:00"] 

883 ... ) 

884 >>> idx.date 

885 array([datetime.date(2020, 1, 1), datetime.date(2020, 2, 1)], dtype=object) 

886 """ 

887 return self._data.date 

888 

889 @property 

890 def time(self) -> npt.NDArray[np.object_]: 

891 """ 

892 Returns numpy array of :class:`datetime.time` objects. 

893 

894 The time part of the Timestamps. 

895 

896 See Also 

897 -------- 

898 DatetimeIndex.timetz : Returns numpy array of :class:`datetime.time` 

899 objects with timezones. The time part of the Timestamps. 

900 DatetimeIndex.date : Returns numpy array of python :class:`datetime.date` 

901 objects. Namely, the date part of Timestamps without time and timezone 

902 information. 

903 

904 Examples 

905 -------- 

906 >>> idx = pd.DatetimeIndex( 

907 ... ["1/1/2020 10:00:00+00:00", "2/1/2020 11:00:00+00:00"] 

908 ... ) 

909 >>> idx.time 

910 array([datetime.time(10, 0), datetime.time(11, 0)], dtype=object) 

911 """ 

912 return self._data.time 

913 

914 @property 

915 def timetz(self) -> npt.NDArray[np.object_]: 

916 """ 

917 Returns numpy array of :class:`datetime.time` objects with timezones. 

918 

919 The time part of the Timestamps. 

920 

921 See Also 

922 -------- 

923 DatetimeIndex.time : Returns numpy array of :class:`datetime.time` objects. 

924 The time part of the Timestamps. 

925 DatetimeIndex.tz : Return the timezone. 

926 

927 Examples 

928 -------- 

929 >>> idx = pd.DatetimeIndex( 

930 ... ["1/1/2020 10:00:00+00:00", "2/1/2020 11:00:00+00:00"] 

931 ... ) 

932 >>> idx.timetz 

933 array([datetime.time(10, 0, tzinfo=datetime.timezone.utc), 

934 datetime.time(11, 0, tzinfo=datetime.timezone.utc)], dtype=object) 

935 """ 

936 return self._data.timetz 

937 

938 def to_pydatetime(self) -> npt.NDArray[np.object_]: 

939 """ 

940 Return an ndarray of ``datetime.datetime`` objects. 

941 

942 This method converts each element in the DatetimeIndex to a native 

943 Python ``datetime.datetime`` object, including timezone information 

944 if present. 

945 

946 Returns 

947 ------- 

948 numpy.ndarray 

949 An ndarray of ``datetime.datetime`` objects. 

950 

951 See Also 

952 -------- 

953 DatetimeIndex.to_julian_date : Converts Datetime Array to float64 ndarray 

954 of Julian Dates. 

955 

956 Examples 

957 -------- 

958 >>> idx = pd.date_range("2018-02-27", periods=3) 

959 >>> idx.to_pydatetime() 

960 array([datetime.datetime(2018, 2, 27, 0, 0), 

961 datetime.datetime(2018, 2, 28, 0, 0), 

962 datetime.datetime(2018, 3, 1, 0, 0)], dtype=object) 

963 """ 

964 return self._data.to_pydatetime() 

965 

966 def std( 

967 self, 

968 axis=None, 

969 dtype=None, 

970 out=None, 

971 ddof: int = 1, 

972 keepdims: bool = False, 

973 skipna: bool = True, 

974 ) -> Timedelta: 

975 """ 

976 Return sample standard deviation over requested axis. 

977 

978 Normalized by `N-1` by default. This can be changed using ``ddof``. 

979 

980 Parameters 

981 ---------- 

982 axis : int, optional 

983 Axis for the function to be applied on. 

984 dtype : None 

985 Unused; for compatibility with :func:`numpy.std`. 

986 out : None 

987 Not supported; for compatibility with :func:`numpy.std`. 

988 ddof : int, default 1 

989 Degrees of Freedom. The divisor used in calculations is `N - ddof`, 

990 where `N` represents the number of elements. 

991 keepdims : bool, default False 

992 Not supported; for compatibility with :func:`numpy.std`. 

993 skipna : bool, default True 

994 Exclude NA/null values. 

995 

996 Returns 

997 ------- 

998 Timedelta 

999 Standard deviation over requested axis. 

1000 

1001 See Also 

1002 -------- 

1003 numpy.ndarray.std : Returns the standard deviation of the array elements 

1004 along given axis. 

1005 Series.std : Return sample standard deviation over requested axis. 

1006 

1007 Examples 

1008 -------- 

1009 >>> idx = pd.date_range("2001-01-01 00:00", periods=3) 

1010 >>> idx 

1011 DatetimeIndex(['2001-01-01', '2001-01-02', '2001-01-03'], 

1012 dtype='datetime64[us]', freq='D') 

1013 >>> idx.std() 

1014 Timedelta('1 days 00:00:00') 

1015 """ 

1016 return self._data.std( 

1017 axis=axis, dtype=dtype, out=out, ddof=ddof, keepdims=keepdims, skipna=skipna 

1018 ) 

1019 

1020 # -------------------------------------------------------------------- 

1021 # methods that dispatch to DatetimeArray and wrap result 

1022 

1023 def strftime(self, date_format) -> Index: 

1024 """ 

1025 Convert to Index using specified date_format. 

1026 

1027 Return an Index of formatted strings specified by date_format, which 

1028 supports the same string format as the python standard library. Details 

1029 of the string format can be found in `python string format 

1030 doc <https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior>`__. 

1031 

1032 Formats supported by the C `strftime` API but not by the python string format 

1033 doc (such as `"%R"`, `"%r"`) are not officially supported and should be 

1034 preferably replaced with their supported equivalents (such as `"%H:%M"`, 

1035 `"%I:%M:%S %p"`). 

1036 Note that `PeriodIndex` support additional directives, detailed in 

1037 `Period.strftime`. 

1038 

1039 Parameters 

1040 ---------- 

1041 date_format : str 

1042 Date format string (e.g. "%Y-%m-%d"). 

1043 

1044 Returns 

1045 ------- 

1046 ndarray[object] 

1047 NumPy ndarray of formatted strings. 

1048 

1049 See Also 

1050 -------- 

1051 to_datetime : Convert the given argument to datetime. 

1052 DatetimeIndex.normalize : Return DatetimeIndex with times to midnight. 

1053 DatetimeIndex.round : Round the DatetimeIndex to the specified freq. 

1054 DatetimeIndex.floor : Floor the DatetimeIndex to the specified freq. 

1055 Timestamp.strftime : Format a single Timestamp. 

1056 Period.strftime : Format a single Period. 

1057 

1058 Examples 

1059 -------- 

1060 >>> rng = pd.date_range(pd.Timestamp("2018-03-10 09:00"), periods=3, freq="s") 

1061 >>> rng.strftime("%B %d, %Y, %r") 

1062 Index(['March 10, 2018, 09:00:00 AM', 'March 10, 2018, 09:00:01 AM', 

1063 'March 10, 2018, 09:00:02 AM'], 

1064 dtype='str') 

1065 """ 

1066 arr = self._data.strftime(date_format) 

1067 return Index(arr, name=self.name, dtype=arr.dtype, copy=False) 

1068 

1069 def month_name(self, locale=None) -> Index: 

1070 """ 

1071 Return the month names with specified locale. 

1072 

1073 This method returns the full name of the month (e.g., "January", "February") 

1074 for each datetime value in the Series/Index. The names can be localized 

1075 to different languages using the locale parameter. 

1076 

1077 Parameters 

1078 ---------- 

1079 locale : str, optional 

1080 Locale determining the language in which to return the month name. 

1081 Default is English locale (``'en_US.utf8'``). Use the command 

1082 ``locale -a`` on your terminal on Unix systems to find your locale 

1083 language code. 

1084 

1085 Returns 

1086 ------- 

1087 Index 

1088 Index of month names. 

1089 

1090 See Also 

1091 -------- 

1092 DatetimeIndex.day_name : Return the day names with specified locale. 

1093 

1094 Examples 

1095 -------- 

1096 >>> idx = pd.date_range(start="2018-01", freq="ME", periods=3) 

1097 >>> idx 

1098 DatetimeIndex(['2018-01-31', '2018-02-28', '2018-03-31'], 

1099 dtype='datetime64[us]', freq='ME') 

1100 >>> idx.month_name() 

1101 Index(['January', 'February', 'March'], dtype='str') 

1102 

1103 Using the ``locale`` parameter you can set a different locale language, 

1104 for example: ``idx.month_name(locale='pt_BR.utf8')`` will return month 

1105 names in Brazilian Portuguese language. 

1106 

1107 >>> idx.month_name(locale="pt_BR.utf8") # doctest: +SKIP 

1108 Index(['Janeiro', 'Fevereiro', 'Março'], dtype='str') 

1109 """ 

1110 arr = self._data.month_name(locale=locale) 

1111 return Index(arr, name=self.name, dtype=arr.dtype, copy=False) 

1112 

1113 def day_name(self, locale=None) -> Index: 

1114 """ 

1115 Return the day names with specified locale. 

1116 

1117 This method returns the full name of the day of the week (e.g., "Monday", 

1118 "Tuesday") for each datetime value in the Series/Index. The names can be 

1119 localized to different languages using the locale parameter. 

1120 

1121 Parameters 

1122 ---------- 

1123 locale : str, optional 

1124 Locale determining the language in which to return the day name. 

1125 Default is English locale (``'en_US.utf8'``). Use the command 

1126 ``locale -a`` on your terminal on Unix systems to find your locale 

1127 language code. 

1128 

1129 Returns 

1130 ------- 

1131 Index 

1132 Index of day names. 

1133 

1134 See Also 

1135 -------- 

1136 DatetimeIndex.month_name : Return the month names with specified locale. 

1137 

1138 Examples 

1139 -------- 

1140 >>> idx = pd.date_range(start="2018-01-01", freq="D", periods=3) 

1141 >>> idx 

1142 DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03'], 

1143 dtype='datetime64[us]', freq='D') 

1144 >>> idx.day_name() 

1145 Index(['Monday', 'Tuesday', 'Wednesday'], dtype='str') 

1146 

1147 Using the ``locale`` parameter you can set a different locale language, 

1148 for example: ``idx.day_name(locale='pt_BR.utf8')`` will return day 

1149 names in Brazilian Portuguese language. 

1150 

1151 >>> idx.day_name(locale="pt_BR.utf8") # doctest: +SKIP 

1152 Index(['Segunda', 'Terça', 'Quarta'], dtype='str') 

1153 """ 

1154 arr = self._data.day_name(locale=locale) 

1155 return Index(arr, name=self.name, dtype=arr.dtype, copy=False) 

1156 

1157 # error: Signature of "round" incompatible with supertype "Index" 

1158 # freq-based, unlike Index.round(decimals) 

1159 def round( # type: ignore[override] 

1160 self, 

1161 freq, 

1162 ambiguous: TimeAmbiguous = "raise", 

1163 nonexistent: TimeNonexistent = "raise", 

1164 ) -> Self: 

1165 """ 

1166 Perform round operation on the data to the specified `freq`. 

1167 

1168 This method rounds each datetime value in the Series/Index to the 

1169 nearest specified frequency using standard rounding rules (round half 

1170 to even). 

1171 

1172 Parameters 

1173 ---------- 

1174 freq : str or Offset 

1175 The frequency level to round the index to. Must be a fixed 

1176 frequency like 's' (second) not 'ME' (month end). See 

1177 :ref:`frequency aliases <timeseries.offset_aliases>` for 

1178 a list of possible `freq` values. 

1179 ambiguous : 'infer', bool-ndarray, 'NaT', default 'raise' 

1180 - 'infer' will attempt to infer fall dst-transition hours based on 

1181 order. Requires that the timestamps are monotonically increasing. 

1182 - bool-ndarray where True signifies a DST time, False designates 

1183 a non-DST time (note that this flag is only applicable for 

1184 ambiguous times) 

1185 - 'NaT' will return NaT where there are ambiguous times 

1186 - 'raise' will raise a ValueError if there are ambiguous 

1187 times. 

1188 nonexistent : 'shift_forward', 'shift_backward', 'NaT', timedelta, \ 

1189 default 'raise' 

1190 A nonexistent time does not exist in a particular timezone 

1191 where clocks moved forward due to DST. 

1192 

1193 - 'shift_forward' will shift the nonexistent time forward to the 

1194 closest existing time 

1195 - 'shift_backward' will shift the nonexistent time backward to the 

1196 closest existing time 

1197 - 'NaT' will return NaT where there are nonexistent times 

1198 - timedelta objects will shift nonexistent times by the timedelta 

1199 - 'raise' will raise a ValueError if there are 

1200 nonexistent times. 

1201 

1202 Returns 

1203 ------- 

1204 DatetimeIndex 

1205 Index with each value rounded to the specified `freq`. 

1206 

1207 Raises 

1208 ------ 

1209 ValueError if the `freq` cannot be converted. 

1210 

1211 See Also 

1212 -------- 

1213 DatetimeIndex.floor : Perform floor operation on the data to the 

1214 specified `freq`. 

1215 DatetimeIndex.ceil : Perform ceil operation on the data to the 

1216 specified `freq`. 

1217 DatetimeIndex.snap : Snap time stamps to nearest occurring frequency. 

1218 

1219 Notes 

1220 ----- 

1221 If the timestamps have a timezone, rounding will take place relative to the 

1222 local ("wall") time and re-localized to the same timezone. When rounding 

1223 near daylight savings time, use ``nonexistent`` and ``ambiguous`` to 

1224 control the re-localization behavior. 

1225 

1226 Examples 

1227 -------- 

1228 >>> rng = pd.date_range("1/1/2018 11:59:00", periods=3, freq="min") 

1229 >>> rng 

1230 DatetimeIndex(['2018-01-01 11:59:00', '2018-01-01 12:00:00', 

1231 '2018-01-01 12:01:00'], 

1232 dtype='datetime64[us]', freq='min') 

1233 >>> rng.round("h") 

1234 DatetimeIndex(['2018-01-01 12:00:00', '2018-01-01 12:00:00', 

1235 '2018-01-01 12:00:00'], 

1236 dtype='datetime64[us]', freq=None) 

1237 

1238 When rounding near a daylight savings time transition, use ``ambiguous`` or 

1239 ``nonexistent`` to control how the timestamp should be re-localized. 

1240 

1241 >>> rng_tz = pd.DatetimeIndex(["2021-10-31 01:30:00"], tz="Europe/Amsterdam") 

1242 >>> rng_tz.round("2h", ambiguous=False) 

1243 DatetimeIndex(['2021-10-31 02:00:00+01:00'], 

1244 dtype='datetime64[us, Europe/Amsterdam]', freq=None) 

1245 >>> rng_tz.round("2h", ambiguous=True) 

1246 DatetimeIndex(['2021-10-31 02:00:00+02:00'], 

1247 dtype='datetime64[us, Europe/Amsterdam]', freq=None) 

1248 """ 

1249 arr = self._data.round(freq, ambiguous, nonexistent) 

1250 return type(self)._simple_new(arr, name=self.name) 

1251 

1252 def floor( 

1253 self, 

1254 freq, 

1255 ambiguous: TimeAmbiguous = "raise", 

1256 nonexistent: TimeNonexistent = "raise", 

1257 ) -> Self: 

1258 """ 

1259 Perform floor operation on the data to the specified `freq`. 

1260 

1261 This method rounds each datetime value in the Series/Index down to 

1262 the specified frequency (i.e., towards negative infinity). 

1263 

1264 Parameters 

1265 ---------- 

1266 freq : str or Offset 

1267 The frequency level to floor the index to. Must be a fixed 

1268 frequency like 's' (second) not 'ME' (month end). See 

1269 :ref:`frequency aliases <timeseries.offset_aliases>` for 

1270 a list of possible `freq` values. 

1271 ambiguous : 'infer', bool-ndarray, 'NaT', default 'raise' 

1272 - 'infer' will attempt to infer fall dst-transition hours based on 

1273 order. Requires that the timestamps are monotonically increasing. 

1274 - bool-ndarray where True signifies a DST time, False designates 

1275 a non-DST time (note that this flag is only applicable for 

1276 ambiguous times) 

1277 - 'NaT' will return NaT where there are ambiguous times 

1278 - 'raise' will raise a ValueError if there are ambiguous 

1279 times. 

1280 nonexistent : 'shift_forward', 'shift_backward', 'NaT', timedelta, \ 

1281 default 'raise' 

1282 A nonexistent time does not exist in a particular timezone 

1283 where clocks moved forward due to DST. 

1284 

1285 - 'shift_forward' will shift the nonexistent time forward to the 

1286 closest existing time 

1287 - 'shift_backward' will shift the nonexistent time backward to the 

1288 closest existing time 

1289 - 'NaT' will return NaT where there are nonexistent times 

1290 - timedelta objects will shift nonexistent times by the timedelta 

1291 - 'raise' will raise a ValueError if there are 

1292 nonexistent times. 

1293 

1294 Returns 

1295 ------- 

1296 DatetimeIndex 

1297 Index with each value floored to the specified `freq`. 

1298 

1299 Raises 

1300 ------ 

1301 ValueError if the `freq` cannot be converted. 

1302 

1303 See Also 

1304 -------- 

1305 DatetimeIndex.round : Perform round operation on the data to the 

1306 specified `freq`. 

1307 DatetimeIndex.ceil : Perform ceil operation on the data to the 

1308 specified `freq`. 

1309 DatetimeIndex.snap : Snap time stamps to nearest occurring frequency. 

1310 

1311 Notes 

1312 ----- 

1313 If the timestamps have a timezone, flooring will take place relative to the 

1314 local ("wall") time and re-localized to the same timezone. When flooring 

1315 near daylight savings time, use ``nonexistent`` and ``ambiguous`` to 

1316 control the re-localization behavior. 

1317 

1318 Examples 

1319 -------- 

1320 >>> rng = pd.date_range("1/1/2018 11:59:00", periods=3, freq="min") 

1321 >>> rng 

1322 DatetimeIndex(['2018-01-01 11:59:00', '2018-01-01 12:00:00', 

1323 '2018-01-01 12:01:00'], 

1324 dtype='datetime64[us]', freq='min') 

1325 >>> rng.floor("h") 

1326 DatetimeIndex(['2018-01-01 11:00:00', '2018-01-01 12:00:00', 

1327 '2018-01-01 12:00:00'], 

1328 dtype='datetime64[us]', freq=None) 

1329 

1330 When rounding near a daylight savings time transition, use ``ambiguous`` or 

1331 ``nonexistent`` to control how the timestamp should be re-localized. 

1332 

1333 >>> rng_tz = pd.DatetimeIndex(["2021-10-31 03:30:00"], tz="Europe/Amsterdam") 

1334 >>> rng_tz.floor("2h", ambiguous=False) 

1335 DatetimeIndex(['2021-10-31 02:00:00+01:00'], 

1336 dtype='datetime64[us, Europe/Amsterdam]', freq=None) 

1337 >>> rng_tz.floor("2h", ambiguous=True) 

1338 DatetimeIndex(['2021-10-31 02:00:00+02:00'], 

1339 dtype='datetime64[us, Europe/Amsterdam]', freq=None) 

1340 """ 

1341 arr = self._data.floor(freq, ambiguous, nonexistent) 

1342 return type(self)._simple_new(arr, name=self.name) 

1343 

1344 def ceil( 

1345 self, 

1346 freq, 

1347 ambiguous: TimeAmbiguous = "raise", 

1348 nonexistent: TimeNonexistent = "raise", 

1349 ) -> Self: 

1350 """ 

1351 Perform ceil operation on the data to the specified `freq`. 

1352 

1353 This method rounds each datetime value in the Series/Index up to 

1354 the specified frequency (i.e., towards positive infinity). 

1355 

1356 Parameters 

1357 ---------- 

1358 freq : str or Offset 

1359 The frequency level to ceil the index to. Must be a fixed 

1360 frequency like 's' (second) not 'ME' (month end). See 

1361 :ref:`frequency aliases <timeseries.offset_aliases>` for 

1362 a list of possible `freq` values. 

1363 ambiguous : 'infer', bool-ndarray, 'NaT', default 'raise' 

1364 - 'infer' will attempt to infer fall dst-transition hours based on 

1365 order. Requires that the timestamps are monotonically increasing. 

1366 - bool-ndarray where True signifies a DST time, False designates 

1367 a non-DST time (note that this flag is only applicable for 

1368 ambiguous times) 

1369 - 'NaT' will return NaT where there are ambiguous times 

1370 - 'raise' will raise a ValueError if there are ambiguous 

1371 times. 

1372 nonexistent : 'shift_forward', 'shift_backward', 'NaT', timedelta, \ 

1373 default 'raise' 

1374 A nonexistent time does not exist in a particular timezone 

1375 where clocks moved forward due to DST. 

1376 

1377 - 'shift_forward' will shift the nonexistent time forward to the 

1378 closest existing time 

1379 - 'shift_backward' will shift the nonexistent time backward to the 

1380 closest existing time 

1381 - 'NaT' will return NaT where there are nonexistent times 

1382 - timedelta objects will shift nonexistent times by the timedelta 

1383 - 'raise' will raise a ValueError if there are 

1384 nonexistent times. 

1385 

1386 Returns 

1387 ------- 

1388 DatetimeIndex 

1389 Index with each value ceiled to the specified `freq`. 

1390 

1391 Raises 

1392 ------ 

1393 ValueError if the `freq` cannot be converted. 

1394 

1395 See Also 

1396 -------- 

1397 DatetimeIndex.round : Perform round operation on the data to the 

1398 specified `freq`. 

1399 DatetimeIndex.floor : Perform floor operation on the data to the 

1400 specified `freq`. 

1401 DatetimeIndex.snap : Snap time stamps to nearest occurring frequency. 

1402 

1403 Notes 

1404 ----- 

1405 If the timestamps have a timezone, ceiling will take place relative to the 

1406 local ("wall") time and re-localized to the same timezone. When ceiling 

1407 near daylight savings time, use ``nonexistent`` and ``ambiguous`` to 

1408 control the re-localization behavior. 

1409 

1410 Examples 

1411 -------- 

1412 >>> rng = pd.date_range("1/1/2018 11:59:00", periods=3, freq="min") 

1413 >>> rng 

1414 DatetimeIndex(['2018-01-01 11:59:00', '2018-01-01 12:00:00', 

1415 '2018-01-01 12:01:00'], 

1416 dtype='datetime64[us]', freq='min') 

1417 >>> rng.ceil("h") 

1418 DatetimeIndex(['2018-01-01 12:00:00', '2018-01-01 12:00:00', 

1419 '2018-01-01 13:00:00'], 

1420 dtype='datetime64[us]', freq=None) 

1421 

1422 When rounding near a daylight savings time transition, use ``ambiguous`` or 

1423 ``nonexistent`` to control how the timestamp should be re-localized. 

1424 

1425 >>> rng_tz = pd.DatetimeIndex(["2021-10-31 01:30:00"], tz="Europe/Amsterdam") 

1426 >>> rng_tz.ceil("h", ambiguous=False) 

1427 DatetimeIndex(['2021-10-31 02:00:00+01:00'], 

1428 dtype='datetime64[us, Europe/Amsterdam]', freq=None) 

1429 >>> rng_tz.ceil("h", ambiguous=True) 

1430 DatetimeIndex(['2021-10-31 02:00:00+02:00'], 

1431 dtype='datetime64[us, Europe/Amsterdam]', freq=None) 

1432 """ 

1433 arr = self._data.ceil(freq, ambiguous, nonexistent) 

1434 return type(self)._simple_new(arr, name=self.name) 

1435 

1436 def normalize(self) -> Self: 

1437 """ 

1438 Convert times to midnight. 

1439 

1440 The time component of the date-time is converted to midnight i.e. 

1441 00:00:00. This is useful in cases, when the time does not matter. 

1442 Length is unaltered. The timezones are unaffected. 

1443 

1444 This method is available on Series with datetime values under 

1445 the ``.dt`` accessor, and directly on Datetime Array/Index. 

1446 

1447 Returns 

1448 ------- 

1449 DatetimeArray, DatetimeIndex or Series 

1450 The same type as the original data. Series will have the same 

1451 name and index. DatetimeIndex will have the same name. 

1452 

1453 See Also 

1454 -------- 

1455 floor : Floor the datetimes to the specified freq. 

1456 ceil : Ceil the datetimes to the specified freq. 

1457 round : Round the datetimes to the specified freq. 

1458 

1459 Examples 

1460 -------- 

1461 >>> idx = pd.date_range( 

1462 ... start="2014-08-01 10:00", freq="h", periods=3, tz="Asia/Calcutta" 

1463 ... ) 

1464 >>> idx 

1465 DatetimeIndex(['2014-08-01 10:00:00+05:30', 

1466 '2014-08-01 11:00:00+05:30', 

1467 '2014-08-01 12:00:00+05:30'], 

1468 dtype='datetime64[us, Asia/Calcutta]', freq='h') 

1469 >>> idx.normalize() 

1470 DatetimeIndex(['2014-08-01 00:00:00+05:30', 

1471 '2014-08-01 00:00:00+05:30', 

1472 '2014-08-01 00:00:00+05:30'], 

1473 dtype='datetime64[us, Asia/Calcutta]', freq=None) 

1474 """ 

1475 data = self._data 

1476 # Inferring frequency from naive normalization is significantly 

1477 # cheaper than tz-aware. 

1478 naive = data._normalize_naive() 

1479 freq = to_offset(naive._inferred_freq_str) 

1480 arr = naive.tz_localize(data.tz) if data.tz is not None else naive 

1481 result = type(self)._simple_new(arr, name=self.name) 

1482 result._freq = freq 

1483 return result 

1484 

1485 def tz_convert(self, tz) -> Self: 

1486 """ 

1487 Convert tz-aware Datetime Array/Index from one time zone to another. 

1488 

1489 This method converts each timestamp in the index to the target time 

1490 zone while preserving the underlying UTC time. The index must already 

1491 be timezone-aware. 

1492 

1493 Parameters 

1494 ---------- 

1495 tz : str, zoneinfo.ZoneInfo, pytz.timezone, dateutil.tz.tzfile, datetime.tzinfo or None 

1496 Time zone for time. Corresponding timestamps would be converted 

1497 to this time zone of the Datetime Array/Index. A `tz` of None will 

1498 convert to UTC and remove the timezone information. 

1499 

1500 Returns 

1501 ------- 

1502 Array or Index 

1503 Datetime Array/Index with target `tz`. 

1504 

1505 Raises 

1506 ------ 

1507 TypeError 

1508 If Datetime Array/Index is tz-naive. 

1509 

1510 See Also 

1511 -------- 

1512 DatetimeIndex.tz : A timezone that has a variable offset from UTC. 

1513 DatetimeIndex.tz_localize : Localize tz-naive DatetimeIndex to a 

1514 given time zone, or remove timezone from a tz-aware DatetimeIndex. 

1515 

1516 Examples 

1517 -------- 

1518 With the `tz` parameter, we can change the DatetimeIndex 

1519 to other time zones: 

1520 

1521 >>> dti = pd.date_range( 

1522 ... start="2014-08-01 09:00", freq="h", periods=3, tz="Europe/Berlin" 

1523 ... ) 

1524 

1525 >>> dti 

1526 DatetimeIndex(['2014-08-01 09:00:00+02:00', 

1527 '2014-08-01 10:00:00+02:00', 

1528 '2014-08-01 11:00:00+02:00'], 

1529 dtype='datetime64[us, Europe/Berlin]', freq='h') 

1530 

1531 >>> dti.tz_convert("US/Central") 

1532 DatetimeIndex(['2014-08-01 02:00:00-05:00', 

1533 '2014-08-01 03:00:00-05:00', 

1534 '2014-08-01 04:00:00-05:00'], 

1535 dtype='datetime64[us, US/Central]', freq='h') 

1536 

1537 With the ``tz=None``, we can remove the timezone (after converting 

1538 to UTC if necessary): 

1539 

1540 >>> dti = pd.date_range( 

1541 ... start="2014-08-01 09:00", freq="h", periods=3, tz="Europe/Berlin" 

1542 ... ) 

1543 

1544 >>> dti 

1545 DatetimeIndex(['2014-08-01 09:00:00+02:00', 

1546 '2014-08-01 10:00:00+02:00', 

1547 '2014-08-01 11:00:00+02:00'], 

1548 dtype='datetime64[us, Europe/Berlin]', freq='h') 

1549 

1550 >>> dti.tz_convert(None) 

1551 DatetimeIndex(['2014-08-01 07:00:00', 

1552 '2014-08-01 08:00:00', 

1553 '2014-08-01 09:00:00'], 

1554 dtype='datetime64[us]', freq='h') 

1555 """ # noqa: E501 

1556 arr = self._data.tz_convert(tz) 

1557 result = type(self)._simple_new(arr, name=self.name, refs=self._references) 

1558 if isinstance(self.freq, Tick): 

1559 result._freq = self.freq 

1560 return result 

1561 

1562 def tz_localize( 

1563 self, 

1564 tz, 

1565 ambiguous: TimeAmbiguous = "raise", 

1566 nonexistent: TimeNonexistent = "raise", 

1567 ) -> Self: 

1568 """ 

1569 Localize tz-naive Datetime Array/Index to tz-aware Datetime Array/Index. 

1570 

1571 This method takes a time zone (tz) naive Datetime Array/Index object 

1572 and makes this time zone aware. It does not move the time to another 

1573 time zone. 

1574 

1575 This method can also be used to do the inverse -- to create a time 

1576 zone unaware object from an aware object. To that end, pass `tz=None`. 

1577 

1578 Parameters 

1579 ---------- 

1580 tz : str, zoneinfo.ZoneInfo, pytz.timezone, dateutil.tz.tzfile, datetime.tzinfo or None 

1581 Time zone to attach to the tz-naive timestamps; the wall time is 

1582 preserved. Passing ``None`` detaches the time zone from a tz-aware 

1583 DatetimeIndex, returning a tz-naive DatetimeIndex with the same 

1584 wall time. 

1585 ambiguous : 'infer', 'NaT', bool array, default 'raise' 

1586 When clocks moved backward due to DST, ambiguous times may arise. 

1587 For example in Central European Time (UTC+01), when going from 

1588 03:00 DST to 02:00 non-DST, 02:30:00 local time occurs both at 

1589 00:30:00 UTC and at 01:30:00 UTC. In such a situation, the 

1590 `ambiguous` parameter dictates how ambiguous times should be 

1591 handled. 

1592 

1593 - 'infer' will attempt to infer fall dst-transition hours based on 

1594 order. Requires that the timestamps are monotonically increasing. 

1595 - bool-ndarray where True signifies a DST time, False signifies a 

1596 non-DST time (note that this flag is only applicable for 

1597 ambiguous times) 

1598 - 'NaT' will return NaT where there are ambiguous times 

1599 - 'raise' will raise a ValueError if there are ambiguous 

1600 times. 

1601 

1602 nonexistent : 'shift_forward', 'shift_backward', 'NaT', timedelta, \ 

1603 default 'raise' 

1604 A nonexistent time does not exist in a particular timezone 

1605 where clocks moved forward due to DST. 

1606 

1607 - 'shift_forward' will shift the nonexistent time forward to the 

1608 closest existing time 

1609 - 'shift_backward' will shift the nonexistent time backward to the 

1610 closest existing time 

1611 - 'NaT' will return NaT where there are nonexistent times 

1612 - timedelta objects will shift nonexistent times by the timedelta 

1613 - 'raise' will raise a ValueError if there are 

1614 nonexistent times. 

1615 

1616 Returns 

1617 ------- 

1618 Same type as self 

1619 Array/Index converted to the specified time zone. 

1620 

1621 Raises 

1622 ------ 

1623 TypeError 

1624 If the Datetime Array/Index is tz-aware and tz is not None. 

1625 

1626 See Also 

1627 -------- 

1628 DatetimeIndex.tz_convert : Convert tz-aware DatetimeIndex from 

1629 one time zone to another. 

1630 

1631 Examples 

1632 -------- 

1633 >>> tz_naive = pd.date_range('2018-03-01 09:00', periods=3) 

1634 >>> tz_naive 

1635 DatetimeIndex(['2018-03-01 09:00:00', '2018-03-02 09:00:00', 

1636 '2018-03-03 09:00:00'], 

1637 dtype='datetime64[us]', freq='D') 

1638 

1639 Localize DatetimeIndex in US/Eastern time zone: 

1640 

1641 >>> tz_aware = tz_naive.tz_localize(tz='US/Eastern') 

1642 >>> tz_aware 

1643 DatetimeIndex(['2018-03-01 09:00:00-05:00', '2018-03-02 09:00:00-05:00', 

1644 '2018-03-03 09:00:00-05:00'], 

1645 dtype='datetime64[us, US/Eastern]', freq='D') 

1646 

1647 With ``tz=None`` we can remove the time zone information while 

1648 preserving the wall time (no conversion to UTC): 

1649 

1650 >>> tz_aware.tz_localize(None) 

1651 DatetimeIndex(['2018-03-01 09:00:00', '2018-03-02 09:00:00', 

1652 '2018-03-03 09:00:00'], 

1653 dtype='datetime64[us]', freq='D') 

1654 

1655 Be careful with DST changes. When there is sequential data, pandas can 

1656 infer the DST time: 

1657 

1658 >>> s = pd.to_datetime(pd.Series(['2018-10-28 01:30:00', 

1659 ... '2018-10-28 02:00:00', 

1660 ... '2018-10-28 02:30:00', 

1661 ... '2018-10-28 02:00:00', 

1662 ... '2018-10-28 02:30:00', 

1663 ... '2018-10-28 03:00:00', 

1664 ... '2018-10-28 03:30:00'])) 

1665 >>> s.dt.tz_localize('CET', ambiguous='infer') 

1666 0 2018-10-28 01:30:00+02:00 

1667 1 2018-10-28 02:00:00+02:00 

1668 2 2018-10-28 02:30:00+02:00 

1669 3 2018-10-28 02:00:00+01:00 

1670 4 2018-10-28 02:30:00+01:00 

1671 5 2018-10-28 03:00:00+01:00 

1672 6 2018-10-28 03:30:00+01:00 

1673 dtype: datetime64[us, CET] 

1674 

1675 In some cases, inferring the DST is impossible. In such cases, you can 

1676 pass an ndarray to the ambiguous parameter to set the DST explicitly 

1677 

1678 >>> s = pd.to_datetime(pd.Series(['2018-10-28 01:20:00', 

1679 ... '2018-10-28 02:36:00', 

1680 ... '2018-10-28 03:46:00'])) 

1681 >>> s.dt.tz_localize('CET', ambiguous=np.array([True, True, False])) 

1682 0 2018-10-28 01:20:00+02:00 

1683 1 2018-10-28 02:36:00+02:00 

1684 2 2018-10-28 03:46:00+01:00 

1685 dtype: datetime64[us, CET] 

1686 

1687 If the DST transition causes nonexistent times, you can shift these 

1688 dates forward or backwards with a timedelta object or `'shift_forward'` 

1689 or `'shift_backward'`. 

1690 

1691 >>> s = pd.to_datetime(pd.Series(['2015-03-29 02:30:00', 

1692 ... '2015-03-29 03:30:00'], dtype="M8[ns]")) 

1693 >>> s.dt.tz_localize('Europe/Warsaw', nonexistent='shift_forward') 

1694 0 2015-03-29 03:00:00+02:00 

1695 1 2015-03-29 03:30:00+02:00 

1696 dtype: datetime64[ns, Europe/Warsaw] 

1697 

1698 >>> s.dt.tz_localize('Europe/Warsaw', nonexistent='shift_backward') 

1699 0 2015-03-29 01:59:59.999999999+01:00 

1700 1 2015-03-29 03:30:00.000000000+02:00 

1701 dtype: datetime64[ns, Europe/Warsaw] 

1702 

1703 >>> s.dt.tz_localize('Europe/Warsaw', nonexistent=pd.Timedelta('1h')) 

1704 0 2015-03-29 03:30:00+02:00 

1705 1 2015-03-29 03:30:00+02:00 

1706 dtype: datetime64[ns, Europe/Warsaw] 

1707 """ # noqa: E501 

1708 freq = self._freq 

1709 arr = self._data.tz_localize(tz, ambiguous, nonexistent) 

1710 result = type(self)._simple_new(arr, name=self.name) 

1711 if timezones.is_utc(arr.tz) or (len(arr) == 1 and arr[0] is not NaT): 

1712 # we can preserve freq 

1713 # TODO: Also for fixed-offsets 

1714 result._freq = freq 

1715 elif arr.tz is None and self._data.tz is None: 

1716 # no-op 

1717 result._freq = freq 

1718 elif ( 

1719 freq is not None 

1720 and not isinstance(freq, Tick) 

1721 and nonexistent in ("raise", "NaT") 

1722 and not arr._hasna 

1723 ): 

1724 # GH#36575 pandas treats non-Tick offsets as wall-time: date_range 

1725 # generates them in wall time and localizes after, and 

1726 # _validate_frequency validates them against wall times (GH#55499). 

1727 # tz_localize leaves wall times unchanged, so freq survives unless 

1728 # we shifted nonexistent times or introduced NaTs. 

1729 result._freq = freq 

1730 return result 

1731 

1732 def to_period(self, freq=None) -> PeriodIndex: 

1733 """ 

1734 Cast to PeriodArray/PeriodIndex at a particular frequency. 

1735 

1736 Converts DatetimeArray/Index to PeriodArray/PeriodIndex. 

1737 

1738 Parameters 

1739 ---------- 

1740 freq : str, optional 

1741 One of pandas' :ref:`period aliases <timeseries.period_aliases>`. 

1742 Will be inferred by default. 

1743 

1744 Returns 

1745 ------- 

1746 PeriodArray/PeriodIndex 

1747 Immutable ndarray holding ordinal values at a particular frequency. 

1748 

1749 Raises 

1750 ------ 

1751 ValueError 

1752 When converting a DatetimeArray/Index with non-regular values, 

1753 so that a frequency cannot be inferred. 

1754 

1755 See Also 

1756 -------- 

1757 PeriodIndex: Immutable ndarray holding ordinal values. 

1758 DatetimeIndex.to_pydatetime: Return DatetimeIndex as object. 

1759 

1760 Examples 

1761 -------- 

1762 >>> df = pd.DataFrame( 

1763 ... {"y": [1, 2, 3]}, 

1764 ... index=pd.to_datetime( 

1765 ... [ 

1766 ... "2000-03-31 00:00:00", 

1767 ... "2000-05-31 00:00:00", 

1768 ... "2000-08-31 00:00:00", 

1769 ... ] 

1770 ... ), 

1771 ... ) 

1772 >>> df.index.to_period("M") 

1773 PeriodIndex(['2000-03', '2000-05', '2000-08'], 

1774 dtype='period[M]') 

1775 

1776 Infer the daily frequency 

1777 

1778 >>> idx = pd.date_range("2017-01-01", periods=2) 

1779 >>> idx.to_period() 

1780 PeriodIndex(['2017-01-01', '2017-01-02'], 

1781 dtype='period[D]') 

1782 """ 

1783 from pandas.core.dtypes.dtypes import PeriodDtype 

1784 

1785 from pandas.core.indexes.api import PeriodIndex 

1786 

1787 from pandas.tseries.frequencies import get_period_alias 

1788 

1789 if freq is None: 

1790 dt_freq = self.freq 

1791 freq = self.freqstr 

1792 if dt_freq is not None and hasattr(dt_freq, "_period_dtype_code"): 

1793 freq = PeriodDtype(dt_freq)._freqstr 

1794 

1795 if freq is None: 

1796 freq = self._inferred_freq_str 

1797 

1798 if freq is not None: 

1799 res = get_period_alias(freq) 

1800 if res is not None: 

1801 freq = res 

1802 arr = self._data.to_period(freq) 

1803 return PeriodIndex._simple_new(arr, name=self.name) 

1804 

1805 def to_julian_date(self) -> Index: 

1806 """ 

1807 Convert Timestamp to a Julian Date. 

1808 

1809 This method returns the number of days as a float since noon January 1, 4713 BC. 

1810 

1811 https://en.wikipedia.org/wiki/Julian_day 

1812 

1813 Returns 

1814 ------- 

1815 ndarray or Index 

1816 Float values that represent each date in Julian Calendar. 

1817 

1818 See Also 

1819 -------- 

1820 Timestamp.to_julian_date : Equivalent method on ``Timestamp`` objects. 

1821 

1822 Examples 

1823 -------- 

1824 >>> idx = pd.DatetimeIndex(["2028-08-12 00:54", "2028-08-12 02:06"]) 

1825 >>> idx.to_julian_date() 

1826 Index([2461995.5375, 2461995.5875], dtype='float64') 

1827 """ 

1828 arr = self._data.to_julian_date() 

1829 return Index._simple_new(arr, name=self.name) 

1830 

1831 def isocalendar(self) -> DataFrame: 

1832 """ 

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

1834 Returns 

1835 ------- 

1836 DataFrame 

1837 With columns year, week and day. 

1838 See Also 

1839 -------- 

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

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

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

1843 three components: year, week and weekday. 

1844 

1845 Examples 

1846 -------- 

1847 >>> idx = pd.date_range(start="2019-12-29", freq="D", periods=4) 

1848 >>> idx.isocalendar() 

1849 year week day 

1850 2019-12-29 2019 52 7 

1851 2019-12-30 2020 1 1 

1852 2019-12-31 2020 1 2 

1853 2020-01-01 2020 1 3 

1854 >>> idx.isocalendar().week 

1855 2019-12-29 52 

1856 2019-12-30 1 

1857 2019-12-31 1 

1858 2020-01-01 1 

1859 Freq: D, Name: week, dtype: UInt32 

1860 """ 

1861 df = self._data.isocalendar() 

1862 return df.set_index(self) 

1863 

1864 # -------------------------------------------------------------------- 

1865 # Constructors 

1866 

1867 def __new__( 

1868 cls, 

1869 data=None, 

1870 freq: Frequency | lib.NoDefault = lib.no_default, 

1871 tz=lib.no_default, 

1872 ambiguous: TimeAmbiguous | lib.NoDefault = lib.no_default, 

1873 dayfirst: bool | lib.NoDefault = lib.no_default, 

1874 yearfirst: bool | lib.NoDefault = lib.no_default, 

1875 dtype: Dtype | None = None, 

1876 copy: bool | None = None, 

1877 name: Hashable | None = None, 

1878 ) -> Self: 

1879 if is_scalar(data): 

1880 cls._raise_scalar_data_error(data) 

1881 

1882 if dayfirst is lib.no_default: 

1883 dayfirst = False 

1884 else: 

1885 warnings.warn( 

1886 f"The 'dayfirst' keyword in {cls.__name__} is deprecated " 

1887 "and will be removed in a future version. " 

1888 "Use pd.to_datetime instead.", 

1889 Pandas4Warning, 

1890 stacklevel=find_stack_level(), 

1891 ) 

1892 if yearfirst is lib.no_default: 

1893 yearfirst = False 

1894 else: 

1895 warnings.warn( 

1896 f"The 'yearfirst' keyword in {cls.__name__} is deprecated " 

1897 "and will be removed in a future version. " 

1898 "Use pd.to_datetime instead.", 

1899 Pandas4Warning, 

1900 stacklevel=find_stack_level(), 

1901 ) 

1902 if ambiguous is lib.no_default: 

1903 ambiguous = "raise" 

1904 else: 

1905 warnings.warn( 

1906 f"The 'ambiguous' keyword in {cls.__name__} is deprecated " 

1907 "and will be removed in a future version. " 

1908 f"Use {cls.__name__}.tz_localize instead.", 

1909 Pandas4Warning, 

1910 stacklevel=find_stack_level(), 

1911 ) 

1912 

1913 # - Cases checked above all return/raise before reaching here - # 

1914 

1915 name = maybe_extract_name(name, data, cls) 

1916 

1917 # GH#63388 

1918 data, copy = cls._maybe_copy_array_input(data, copy, dtype) 

1919 

1920 if ( 

1921 isinstance(data, DatetimeArray) 

1922 and freq is lib.no_default 

1923 and tz is lib.no_default 

1924 and dtype is None 

1925 ): 

1926 # fastpath, similar logic in TimedeltaIndex.__new__; 

1927 # Note in this particular case we retain non-nano. 

1928 if copy: 

1929 data = data.copy() 

1930 return cls._simple_new(data, name=name) 

1931 

1932 inferred_freq = data.freq if isinstance(data, DatetimeIndex) else None 

1933 

1934 dtarr = DatetimeArray._from_sequence_not_strict( 

1935 data, 

1936 dtype=dtype, 

1937 copy=copy, 

1938 tz=tz, 

1939 dayfirst=dayfirst, 

1940 yearfirst=yearfirst, 

1941 ambiguous=ambiguous, 

1942 ) 

1943 

1944 refs = None 

1945 if not copy and isinstance(data, (Index, ABCSeries)): 

1946 refs = data._references 

1947 

1948 subarr = cls._simple_new(dtarr, name=name, refs=refs) 

1949 subarr._pin_freq(freq, inferred_freq) 

1950 return subarr 

1951 

1952 # -------------------------------------------------------------------- 

1953 

1954 @cache_readonly 

1955 def _is_dates_only(self) -> bool: 

1956 """ 

1957 Return a boolean if we are only dates (and don't have a timezone) 

1958 

1959 Returns 

1960 ------- 

1961 bool 

1962 """ 

1963 if isinstance(self.freq, Tick): 

1964 delta = Timedelta(self.freq) 

1965 

1966 if delta % dt.timedelta(days=1) != dt.timedelta(days=0): 

1967 return False 

1968 

1969 return self._values._is_dates_only 

1970 

1971 def __reduce__(self): 

1972 d = {"data": self._data, "name": self.name, "freq": self._freq} 

1973 return _new_DatetimeIndex, (type(self), d), None 

1974 

1975 def _is_comparable_dtype(self, dtype: DtypeObj) -> bool: 

1976 """ 

1977 Can we compare values of the given dtype to our own? 

1978 """ 

1979 if isinstance(dtype, ArrowDtype): 

1980 # GH#62277 

1981 if dtype.kind != "M": 

1982 return False 

1983 

1984 import pyarrow as pa 

1985 

1986 pa_dtype = dtype.pyarrow_dtype 

1987 if not pa.types.is_timestamp(pa_dtype): 

1988 # GH#62051 date types (date32, date64) are not 

1989 # comparable with DatetimeIndex 

1990 return False 

1991 if (pa_dtype.tz is None) ^ (self.tz is None): 

1992 return False 

1993 return True 

1994 

1995 if self.tz is not None: 

1996 # If we have tz, we can compare to tzaware 

1997 return isinstance(dtype, DatetimeTZDtype) 

1998 # if we dont have tz, we can only compare to tznaive 

1999 return lib.is_np_dtype(dtype, "M") 

2000 

2001 # -------------------------------------------------------------------- 

2002 # Rendering Methods 

2003 

2004 def _formatter_func(self, val) -> str: 

2005 # Note this is equivalent to the DatetimeIndexOpsMixin method but 

2006 # uses the maybe-cached self._is_dates_only instead of re-computing it. 

2007 return f"'{self._date_formatter(val)}'" 

2008 

2009 @cache_readonly 

2010 def _date_formatter(self): 

2011 from pandas.io.formats.format import get_format_datetime64 

2012 

2013 return get_format_datetime64(is_dates_only=self._is_dates_only) 

2014 

2015 # -------------------------------------------------------------------- 

2016 # Set Operation Methods 

2017 

2018 def _can_range_setop(self, other) -> bool: 

2019 # GH 46702: If self or other have non-UTC tzs, DST transitions prevent 

2020 # range representation due to no singular step 

2021 if ( 

2022 self.tz is not None 

2023 and not timezones.is_utc(self.tz) 

2024 and not timezones.is_fixed_offset(self.tz) 

2025 ): 

2026 return False 

2027 if ( 

2028 other.tz is not None 

2029 and not timezones.is_utc(other.tz) 

2030 and not timezones.is_fixed_offset(other.tz) 

2031 ): 

2032 return False 

2033 return super()._can_range_setop(other) 

2034 

2035 # -------------------------------------------------------------------- 

2036 

2037 def _get_time_micros(self) -> npt.NDArray[np.int64]: 

2038 """ 

2039 Return the number of microseconds since midnight. 

2040 

2041 Returns 

2042 ------- 

2043 ndarray[int64_t] 

2044 """ 

2045 values = self._data._local_timestamps() 

2046 

2047 ppd = periods_per_day(self._data._creso) 

2048 

2049 frac = values % ppd 

2050 if self.unit == "ns": 

2051 micros = frac // 1000 

2052 elif self.unit == "us": 

2053 micros = frac 

2054 elif self.unit == "ms": 

2055 micros = frac * 1000 

2056 elif self.unit == "s": 

2057 micros = frac * 1_000_000 

2058 else: # pragma: no cover 

2059 raise NotImplementedError(self.unit) 

2060 

2061 micros[self._isnan] = -1 

2062 return micros 

2063 

2064 def snap(self, freq: Frequency = "S") -> DatetimeIndex: 

2065 """ 

2066 Snap time stamps to nearest occurring frequency. 

2067 

2068 Each timestamp in the index is adjusted to the nearest occurrence of 

2069 the specified frequency, snapping backward or forward as appropriate. 

2070 

2071 Parameters 

2072 ---------- 

2073 freq : str, Timedelta, datetime.timedelta, or DateOffset, default 'S' 

2074 Frequency strings can have multiples, e.g. '5h'. See 

2075 :ref:`here <timeseries.offset_aliases>` for a list of 

2076 frequency aliases. 

2077 

2078 Returns 

2079 ------- 

2080 DatetimeIndex 

2081 Time stamps to nearest occurring `freq`. 

2082 

2083 See Also 

2084 -------- 

2085 DatetimeIndex.round : Perform round operation on the data to the 

2086 specified `freq`. 

2087 DatetimeIndex.floor : Perform floor operation on the data to the 

2088 specified `freq`. 

2089 

2090 Examples 

2091 -------- 

2092 >>> idx = pd.DatetimeIndex( 

2093 ... ["2023-01-01", "2023-01-02", "2023-02-01", "2023-02-02"], 

2094 ... dtype="M8[ns]", 

2095 ... ) 

2096 >>> idx 

2097 DatetimeIndex(['2023-01-01', '2023-01-02', '2023-02-01', '2023-02-02'], 

2098 dtype='datetime64[ns]', freq=None) 

2099 >>> idx.snap("MS") 

2100 DatetimeIndex(['2023-01-01', '2023-01-01', '2023-02-01', '2023-02-01'], 

2101 dtype='datetime64[ns]', freq=None) 

2102 """ 

2103 # Superdumb, punting on any optimizing 

2104 freq = to_offset(freq) 

2105 

2106 dta = self._data.copy() 

2107 

2108 for i, v in enumerate(self): 

2109 s = v 

2110 if not freq.is_on_offset(s): 

2111 t0 = freq.rollback(s) 

2112 t1 = freq.rollforward(s) 

2113 if abs(s - t0) < abs(t1 - s): 

2114 s = t0 

2115 else: 

2116 s = t1 

2117 dta[i] = s 

2118 

2119 return DatetimeIndex._simple_new(dta, name=self.name) 

2120 

2121 # -------------------------------------------------------------------- 

2122 # Indexing Methods 

2123 

2124 def _parsed_string_to_bounds( 

2125 self, reso: Resolution, parsed: dt.datetime 

2126 ) -> tuple[Timestamp, Timestamp]: 

2127 """ 

2128 Calculate datetime bounds for parsed time string and its resolution. 

2129 

2130 Parameters 

2131 ---------- 

2132 reso : Resolution 

2133 Resolution provided by parsed string. 

2134 parsed : datetime 

2135 Datetime from parsed string. 

2136 

2137 Returns 

2138 ------- 

2139 lower, upper: pd.Timestamp 

2140 """ 

2141 freq = OFFSET_TO_PERIOD_FREQSTR.get(reso.attr_abbrev, reso.attr_abbrev) 

2142 per = Period(parsed, freq=freq) 

2143 start = per.start_time 

2144 # Can't use end_time here bc that will subtract a microsecond 

2145 # instead of a nanosecond 

2146 end = (per + 1).start_time - np.timedelta64(1, "ns") 

2147 start = start.as_unit(self.unit) 

2148 end = end.as_unit(self.unit) 

2149 

2150 # GH 24076 

2151 # If an incoming date string contained a UTC offset, need to localize 

2152 # the parsed date to this offset first before aligning with the index's 

2153 # timezone 

2154 start = start.tz_localize(parsed.tzinfo) 

2155 end = end.tz_localize(parsed.tzinfo) 

2156 

2157 if parsed.tzinfo is not None: 

2158 if self.tz is None: 

2159 raise ValueError( 

2160 "The index must be timezone aware when indexing " 

2161 "with a date string with a UTC offset" 

2162 ) 

2163 # The flipped case with parsed.tz is None and self.tz is not None 

2164 # is ruled out bc parsed and reso are produced by _parse_with_reso, 

2165 # which localizes parsed. 

2166 return start, end 

2167 

2168 def _parse_with_reso(self, label: str) -> tuple[Timestamp, Resolution]: 

2169 parsed, reso = super()._parse_with_reso(label) 

2170 

2171 parsed = Timestamp(parsed) 

2172 

2173 if self.tz is not None and parsed.tzinfo is None: 

2174 # we special-case timezone-naive strings and timezone-aware 

2175 # DatetimeIndex 

2176 # https://github.com/pandas-dev/pandas/pull/36148#issuecomment-687883081 

2177 parsed = parsed.tz_localize(self.tz) 

2178 

2179 return parsed, reso 

2180 

2181 def _disallow_mismatched_indexing(self, key) -> None: 

2182 """ 

2183 Check for mismatched-tzawareness indexing and re-raise as KeyError. 

2184 """ 

2185 # we get here with isinstance(key, self._data._recognized_scalars) 

2186 try: 

2187 # GH#36148 

2188 self._data._assert_tzawareness_compat(key) 

2189 except TypeError as err: 

2190 raise KeyError(key) from err 

2191 

2192 def get_loc(self, key): 

2193 """ 

2194 Get integer location for requested label 

2195 

2196 Returns 

2197 ------- 

2198 loc : int 

2199 """ 

2200 self._check_indexing_error(key) 

2201 

2202 orig_key = key 

2203 if is_valid_na_for_dtype(key, self.dtype): 

2204 key = NaT 

2205 

2206 if isinstance(key, self._data._recognized_scalars): 

2207 # needed to localize naive datetimes 

2208 self._disallow_mismatched_indexing(key) 

2209 key = Timestamp(key) 

2210 

2211 elif isinstance(key, str): 

2212 try: 

2213 parsed, reso = self._parse_with_reso(key) 

2214 except ValueError as err: 

2215 raise KeyError(key) from err 

2216 self._disallow_mismatched_indexing(parsed) 

2217 

2218 if self._can_partial_date_slice(reso): 

2219 try: 

2220 return self._partial_date_slice(reso, parsed) 

2221 except KeyError as err: 

2222 raise KeyError(key) from err 

2223 

2224 key = parsed 

2225 

2226 elif isinstance(key, dt.timedelta): 

2227 # GH#20464 

2228 raise TypeError( 

2229 f"Cannot index {type(self).__name__} with {type(key).__name__}" 

2230 ) 

2231 

2232 elif isinstance(key, dt.time): 

2233 return self.indexer_at_time(key) 

2234 

2235 else: 

2236 # unrecognized type 

2237 raise KeyError(key) 

2238 

2239 try: 

2240 return Index.get_loc(self, key) 

2241 except KeyError as err: 

2242 raise KeyError(orig_key) from err 

2243 

2244 def _maybe_cast_slice_bound(self, label, side: str): 

2245 """ 

2246 This function should be overloaded in subclasses that allow non-trivial 

2247 casting on label-slice bounds, e.g. datetime-like indices allowing 

2248 strings containing formatted datetimes. 

2249 

2250 Parameters 

2251 ---------- 

2252 label : object 

2253 side : {'left', 'right'} 

2254 

2255 Returns 

2256 ------- 

2257 label : object 

2258 

2259 Notes 

2260 ----- 

2261 Value of `side` parameter should be validated in caller. 

2262 """ 

2263 # GH#42855 handle date here instead of get_slice_bound 

2264 if isinstance(label, dt.date) and not isinstance(label, dt.datetime): 

2265 # Pandas supports slicing with dates, treated as datetimes at midnight. 

2266 # https://github.com/pandas-dev/pandas/issues/31501 

2267 label = Timestamp(label).to_pydatetime() 

2268 warnings.warn( 

2269 # GH#35830 deprecate last remaining inconsistent date treatment 

2270 "Slicing with a datetime.date object is deprecated. " 

2271 "Explicitly cast to Timestamp instead.", 

2272 Pandas4Warning, 

2273 stacklevel=find_stack_level(), 

2274 ) 

2275 

2276 label = super()._maybe_cast_slice_bound(label, side) 

2277 self._data._assert_tzawareness_compat(label) 

2278 return Timestamp(label) 

2279 

2280 def slice_indexer(self, start=None, end=None, step=None): 

2281 """ 

2282 Return indexer for specified label slice. 

2283 Index.slice_indexer, customized to handle time slicing. 

2284 

2285 In addition to functionality provided by Index.slice_indexer, does the 

2286 following: 

2287 

2288 - if both `start` and `end` are instances of `datetime.time`, it 

2289 invokes `indexer_between_time` 

2290 - if `start` and `end` are both either string or None perform 

2291 value-based selection in non-monotonic cases. 

2292 

2293 """ 

2294 # For historical reasons DatetimeIndex supports slices between two 

2295 # instances of datetime.time as if it were applying a slice mask to 

2296 # an array of (self.hour, self.minute, self.seconds, self.microsecond). 

2297 if isinstance(start, dt.time) and isinstance(end, dt.time): 

2298 if step is not None and step != 1: 

2299 raise ValueError("Must have step size of 1 with time slices") 

2300 return self.indexer_between_time(start, end) 

2301 

2302 if isinstance(start, dt.time) or isinstance(end, dt.time): 

2303 raise KeyError("Cannot mix time and non-time slice keys") 

2304 

2305 def check_str_or_none(point) -> bool: 

2306 return point is not None and not isinstance(point, str) 

2307 

2308 # GH#33146 if start and end are combinations of str and None and Index is not 

2309 # monotonic, we can not use Index.slice_indexer because it does not honor the 

2310 # actual elements, is only searching for start and end 

2311 if ( 

2312 check_str_or_none(start) 

2313 or check_str_or_none(end) 

2314 or self.is_monotonic_increasing 

2315 ): 

2316 return Index.slice_indexer(self, start, end, step) 

2317 

2318 mask = np.array(True) 

2319 in_index = True 

2320 if start is not None: 

2321 start_casted = self._maybe_cast_slice_bound(start, "left") 

2322 mask = start_casted <= self 

2323 in_index &= (start_casted == self).any() 

2324 

2325 if end is not None: 

2326 end_casted = self._maybe_cast_slice_bound(end, "right") 

2327 mask = (self <= end_casted) & mask 

2328 in_index &= (end_casted == self).any() 

2329 

2330 if not in_index: 

2331 raise KeyError( 

2332 "Value based partial slicing on non-monotonic DatetimeIndexes " 

2333 "with non-existing keys is not allowed.", 

2334 ) 

2335 indexer = mask.nonzero()[0][::step] 

2336 if len(indexer) == len(self): 

2337 return slice(None) 

2338 else: 

2339 return indexer 

2340 

2341 # -------------------------------------------------------------------- 

2342 

2343 @property 

2344 def inferred_type(self) -> str: 

2345 # b/c datetime is represented as microseconds since the epoch, make 

2346 # sure we can't have ambiguous indexing 

2347 return "datetime64" 

2348 

2349 def indexer_at_time(self, time, asof: bool = False) -> npt.NDArray[np.intp]: 

2350 """ 

2351 Return index locations of values at particular time of day. 

2352 

2353 This method returns the integer indices of the DatetimeIndex entries 

2354 that match the specified time of day, regardless of the date. 

2355 

2356 Parameters 

2357 ---------- 

2358 time : datetime.time or str 

2359 Time passed in either as object (datetime.time) or as string in 

2360 appropriate format ("%H:%M", "%H%M", "%I:%M%p", "%I%M%p", 

2361 "%H:%M:%S", "%H%M%S", "%I:%M:%S%p", "%I%M%S%p"). 

2362 asof : bool, default False 

2363 This parameter is currently not supported. 

2364 

2365 Returns 

2366 ------- 

2367 np.ndarray[np.intp] 

2368 Index locations of values at given `time` of day. 

2369 

2370 See Also 

2371 -------- 

2372 indexer_between_time : Get index locations of values between particular 

2373 times of day. 

2374 DataFrame.at_time : Select values at particular time of day. 

2375 

2376 Examples 

2377 -------- 

2378 >>> idx = pd.DatetimeIndex( 

2379 ... ["1/1/2020 10:00", "2/1/2020 11:00", "3/1/2020 10:00"] 

2380 ... ) 

2381 >>> idx.indexer_at_time("10:00") 

2382 array([0, 2]) 

2383 """ 

2384 if asof: 

2385 raise NotImplementedError("'asof' argument is not supported") 

2386 

2387 if isinstance(time, str): 

2388 from dateutil.parser import parse 

2389 

2390 orig = time 

2391 try: 

2392 alt = to_time(time) 

2393 except ValueError: 

2394 warnings.warn( 

2395 # GH#50839 

2396 f"The string '{orig}' cannot be parsed using pd.core.tools.to_time " 

2397 f"and in a future version will raise. " 

2398 "Use an unambiguous time string format or explicitly cast to " 

2399 "`datetime.time` before calling.", 

2400 Pandas4Warning, 

2401 stacklevel=find_stack_level(), 

2402 ) 

2403 time = parse(time).time() 

2404 else: 

2405 try: 

2406 time = parse(time).time() 

2407 except ValueError: 

2408 # e.g. '23550' raises dateutil.parser._parser.ParserError 

2409 time = alt 

2410 if alt != time: 

2411 warnings.warn( 

2412 # GH#50839 

2413 f"The string '{orig}' is currently parsed as {time} " 

2414 f"but in a future version will be parsed as {alt}, consistent" 

2415 "with `between_time` behavior. To avoid this warning, " 

2416 "use an unambiguous string format or explicitly cast to " 

2417 "`datetime.time` before calling.", 

2418 Pandas4Warning, 

2419 stacklevel=find_stack_level(), 

2420 ) 

2421 

2422 if time.tzinfo: 

2423 if self.tz is None: 

2424 raise ValueError("Index must be timezone aware.") 

2425 time_micros = self.tz_convert(time.tzinfo)._get_time_micros() 

2426 else: 

2427 time_micros = self._get_time_micros() 

2428 micros = _time_to_micros(time) 

2429 return (time_micros == micros).nonzero()[0] 

2430 

2431 def indexer_between_time( 

2432 self, start_time, end_time, include_start: bool = True, include_end: bool = True 

2433 ) -> npt.NDArray[np.intp]: 

2434 """ 

2435 Return index locations of values between particular times of day. 

2436 

2437 This method returns the integer indices of the DatetimeIndex entries 

2438 whose time-of-day components fall within the specified range. 

2439 

2440 Parameters 

2441 ---------- 

2442 start_time, end_time : datetime.time, str 

2443 Time passed either as object (datetime.time) or as string in 

2444 appropriate format ("%H:%M", "%H%M", "%I:%M%p", "%I%M%p", 

2445 "%H:%M:%S", "%H%M%S", "%I:%M:%S%p","%I%M%S%p"). 

2446 include_start : bool, default True 

2447 Include boundaries; whether to set start bound as closed or open. 

2448 include_end : bool, default True 

2449 Include boundaries; whether to set end bound as closed or open. 

2450 

2451 Returns 

2452 ------- 

2453 np.ndarray[np.intp] 

2454 Index locations of values between particular times of day. 

2455 

2456 See Also 

2457 -------- 

2458 indexer_at_time : Get index locations of values at particular time of day. 

2459 DataFrame.between_time : Select values between particular times of day. 

2460 

2461 Examples 

2462 -------- 

2463 >>> idx = pd.date_range("2023-01-01", periods=4, freq="h") 

2464 >>> idx 

2465 DatetimeIndex(['2023-01-01 00:00:00', '2023-01-01 01:00:00', 

2466 '2023-01-01 02:00:00', '2023-01-01 03:00:00'], 

2467 dtype='datetime64[us]', freq='h') 

2468 >>> idx.indexer_between_time("00:00", "2:00", include_end=False) 

2469 array([0, 1]) 

2470 """ 

2471 start_time = to_time(start_time) 

2472 end_time = to_time(end_time) 

2473 time_micros = self._get_time_micros() 

2474 start_micros = _time_to_micros(start_time) 

2475 end_micros = _time_to_micros(end_time) 

2476 

2477 if include_start and include_end: 

2478 lop = rop = operator.le 

2479 elif include_start: 

2480 lop = operator.le 

2481 rop = operator.lt 

2482 elif include_end: 

2483 lop = operator.lt 

2484 rop = operator.le 

2485 else: 

2486 lop = rop = operator.lt 

2487 

2488 if start_time <= end_time: 

2489 join_op = operator.and_ 

2490 else: 

2491 join_op = operator.or_ 

2492 

2493 mask = join_op(lop(start_micros, time_micros), rop(time_micros, end_micros)) 

2494 

2495 return mask.nonzero()[0] 

2496 

2497 

2498@set_module("pandas") 

2499def date_range( 

2500 start=None, 

2501 end=None, 

2502 periods=None, 

2503 freq=None, 

2504 tz=None, 

2505 normalize: bool = False, 

2506 name: Hashable | None = None, 

2507 inclusive: IntervalClosedType = "both", 

2508 *, 

2509 unit: TimeUnit | None = None, 

2510 ambiguous: TimeAmbiguous = "raise", 

2511 nonexistent: TimeNonexistent = "raise", 

2512 **kwargs, 

2513) -> DatetimeIndex: 

2514 """ 

2515 Return a fixed frequency DatetimeIndex. 

2516 

2517 Returns the range of equally spaced time points (where the difference between any 

2518 two adjacent points is specified by the given frequency) such that they fall in the 

2519 range `[start, end]` , where the first one and the last one are, resp., the first 

2520 and last time points in that range that fall on the boundary of ``freq`` (if given 

2521 as a frequency string) or that are valid for ``freq`` (if given as a 

2522 :class:`pandas.tseries.offsets.DateOffset`). If ``freq`` is positive, the points 

2523 satisfy `start <[=] x <[=] end`, and if ``freq`` is negative, the points satisfy 

2524 `end <[=] x <[=] start`. (If exactly one of ``start``, ``end``, or ``freq`` is *not* 

2525 specified, this missing parameter can be computed given ``periods``, the number of 

2526 timesteps in the range. See the note below.) 

2527 

2528 Parameters 

2529 ---------- 

2530 start : str or datetime-like, optional 

2531 Left bound for generating dates. 

2532 end : str or datetime-like, optional 

2533 Right bound for generating dates. 

2534 periods : int, optional 

2535 Number of periods to generate. 

2536 freq : str, Timedelta, datetime.timedelta, or DateOffset, default 'D' 

2537 Frequency strings can have multiples, e.g. '5h'. See 

2538 :ref:`here <timeseries.offset_aliases>` for a list of 

2539 frequency aliases. 

2540 tz : str or tzinfo, optional 

2541 Time zone name for returning localized DatetimeIndex, for example 

2542 'Asia/Hong_Kong'. By default, the resulting DatetimeIndex is 

2543 timezone-naive unless timezone-aware datetime-likes are passed. 

2544 normalize : bool, default False 

2545 Normalize start/end dates to midnight before generating date range. 

2546 name : Hashable, default None 

2547 Name of the resulting DatetimeIndex. 

2548 inclusive : {"both", "neither", "left", "right"}, default "both" 

2549 Include boundaries; Whether to set each bound as closed or open. 

2550 unit : {'s', 'ms', 'us', 'ns', None}, default None 

2551 Specify the desired resolution of the result. 

2552 If not specified, this is inferred from the 'start', 'end', and 'freq' 

2553 using the same inference as :class:`Timestamp` taking the highest 

2554 resolution of the three that are provided. 

2555 

2556 .. versionadded:: 2.0.0 

2557 ambiguous : 'infer', bool-ndarray, 'NaT', default 'raise' 

2558 When clocks moved backward due to DST, ambiguous times may arise. 

2559 For example in Central European Time (UTC+01), when going from 03:00 

2560 DST to 02:00 non-DST, 02:30:00 local time occurs both at 00:30:00 UTC 

2561 and at 01:30:00 UTC. In such a situation, the `ambiguous` parameter 

2562 dictates how ambiguous times should be handled. 

2563 

2564 - 'infer' will attempt to infer fall dst-transition hours based on 

2565 order. Requires that the timestamps are monotonically increasing. 

2566 - bool-ndarray where True signifies a DST time, False signifies a 

2567 non-DST time (note that this flag is only applicable for ambiguous 

2568 times) 

2569 - 'NaT' will return NaT where there are ambiguous times 

2570 - 'raise' will raise a ValueError if there are ambiguous times. 

2571 nonexistent : 'shift_forward', 'shift_backward', 'NaT', timedelta, \ 

2572 default 'raise' 

2573 A nonexistent time does not exist in a particular timezone 

2574 where clocks moved forward due to DST. 

2575 

2576 - 'shift_forward' will shift the nonexistent time forward to the 

2577 closest existing time 

2578 - 'shift_backward' will shift the nonexistent time backward to the 

2579 closest existing time 

2580 - 'NaT' will return NaT where there are nonexistent times 

2581 - timedelta objects will shift nonexistent times by the timedelta 

2582 - 'raise' will raise a ValueError if there are nonexistent times. 

2583 **kwargs 

2584 For compatibility. Has no effect on the result. 

2585 

2586 Returns 

2587 ------- 

2588 DatetimeIndex 

2589 A DatetimeIndex object of the generated dates. 

2590 

2591 See Also 

2592 -------- 

2593 DatetimeIndex : An immutable container for datetimes. 

2594 timedelta_range : Return a fixed frequency TimedeltaIndex. 

2595 period_range : Return a fixed frequency PeriodIndex. 

2596 interval_range : Return a fixed frequency IntervalIndex. 

2597 

2598 Notes 

2599 ----- 

2600 Of the four parameters ``start``, ``end``, ``periods``, and ``freq``, 

2601 a maximum of three can be specified at once. Of the three parameters 

2602 ``start``, ``end``, and ``periods``, at least two must be specified. 

2603 If ``freq`` is omitted, the resulting ``DatetimeIndex`` will have 

2604 ``periods`` linearly spaced elements between ``start`` and ``end`` 

2605 (closed on both sides). 

2606 

2607 To learn more about the frequency strings, please see 

2608 :ref:`this link<timeseries.offset_aliases>`. 

2609 

2610 Examples 

2611 -------- 

2612 **Specifying the values** 

2613 

2614 The next four examples generate the same `DatetimeIndex`, but vary 

2615 the combination of `start`, `end` and `periods`. 

2616 

2617 Specify `start` and `end`, with the default daily frequency. 

2618 

2619 >>> pd.date_range(start="1/1/2018", end="1/08/2018") 

2620 DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04', 

2621 '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08'], 

2622 dtype='datetime64[us]', freq='D') 

2623 

2624 Specify timezone-aware `start` and `end`, with the default daily frequency. 

2625 

2626 >>> pd.date_range( 

2627 ... start=pd.to_datetime("1/1/2018").tz_localize("Europe/Berlin"), 

2628 ... end=pd.to_datetime("1/08/2018").tz_localize("Europe/Berlin"), 

2629 ... ) 

2630 DatetimeIndex(['2018-01-01 00:00:00+01:00', '2018-01-02 00:00:00+01:00', 

2631 '2018-01-03 00:00:00+01:00', '2018-01-04 00:00:00+01:00', 

2632 '2018-01-05 00:00:00+01:00', '2018-01-06 00:00:00+01:00', 

2633 '2018-01-07 00:00:00+01:00', '2018-01-08 00:00:00+01:00'], 

2634 dtype='datetime64[us, Europe/Berlin]', freq='D') 

2635 

2636 Specify `start` and `periods`, the number of periods (days). 

2637 

2638 >>> pd.date_range(start="1/1/2018", periods=8) 

2639 DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04', 

2640 '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08'], 

2641 dtype='datetime64[us]', freq='D') 

2642 

2643 Specify `end` and `periods`, the number of periods (days). 

2644 

2645 >>> pd.date_range(end="1/1/2018", periods=8) 

2646 DatetimeIndex(['2017-12-25', '2017-12-26', '2017-12-27', '2017-12-28', 

2647 '2017-12-29', '2017-12-30', '2017-12-31', '2018-01-01'], 

2648 dtype='datetime64[us]', freq='D') 

2649 

2650 Specify `start`, `end`, and `periods`; the frequency is generated 

2651 automatically (linearly spaced). 

2652 

2653 >>> pd.date_range(start="2018-04-24", end="2018-04-27", periods=3) 

2654 DatetimeIndex(['2018-04-24 00:00:00', '2018-04-25 12:00:00', 

2655 '2018-04-27 00:00:00'], 

2656 dtype='datetime64[us]', freq=None) 

2657 

2658 **Other Parameters** 

2659 

2660 Changed the `freq` (frequency) to ``'ME'`` (month end frequency). 

2661 

2662 >>> pd.date_range(start="1/1/2018", periods=5, freq="ME") 

2663 DatetimeIndex(['2018-01-31', '2018-02-28', '2018-03-31', '2018-04-30', 

2664 '2018-05-31'], 

2665 dtype='datetime64[us]', freq='ME') 

2666 

2667 Multiples are allowed 

2668 

2669 >>> pd.date_range(start="1/1/2018", periods=5, freq="3ME") 

2670 DatetimeIndex(['2018-01-31', '2018-04-30', '2018-07-31', '2018-10-31', 

2671 '2019-01-31'], 

2672 dtype='datetime64[us]', freq='3ME') 

2673 

2674 `freq` can also be specified as an Offset object. 

2675 

2676 >>> pd.date_range(start="1/1/2018", periods=5, freq=pd.offsets.MonthEnd(3)) 

2677 DatetimeIndex(['2018-01-31', '2018-04-30', '2018-07-31', '2018-10-31', 

2678 '2019-01-31'], 

2679 dtype='datetime64[us]', freq='3ME') 

2680 

2681 Use :class:`pandas.DateOffset` for calendar steps that are not anchored to 

2682 the start or end of a period. 

2683 

2684 >>> pd.date_range(end="2017-03-12", periods=3, freq=pd.DateOffset(years=1)) 

2685 DatetimeIndex(['2015-03-12', '2016-03-12', '2017-03-12'], 

2686 dtype='datetime64[us]', freq='<DateOffset: years=1>') 

2687 

2688 Specify `tz` to set the timezone. 

2689 

2690 >>> pd.date_range(start="1/1/2018", periods=5, tz="Asia/Tokyo") 

2691 DatetimeIndex(['2018-01-01 00:00:00+09:00', '2018-01-02 00:00:00+09:00', 

2692 '2018-01-03 00:00:00+09:00', '2018-01-04 00:00:00+09:00', 

2693 '2018-01-05 00:00:00+09:00'], 

2694 dtype='datetime64[us, Asia/Tokyo]', freq='D') 

2695 

2696 `inclusive` controls whether to include `start` and `end` that are on the 

2697 boundary. The default, "both", includes boundary points on either end. 

2698 

2699 >>> pd.date_range(start="2017-01-01", end="2017-01-04", inclusive="both") 

2700 DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03', '2017-01-04'], 

2701 dtype='datetime64[us]', freq='D') 

2702 

2703 Use ``inclusive='left'`` to exclude `end` if it falls on the boundary. 

2704 

2705 >>> pd.date_range(start="2017-01-01", end="2017-01-04", inclusive="left") 

2706 DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03'], 

2707 dtype='datetime64[us]', freq='D') 

2708 

2709 Use ``inclusive='right'`` to exclude `start` if it falls on the boundary, and 

2710 similarly ``inclusive='neither'`` will exclude both `start` and `end`. 

2711 

2712 >>> pd.date_range(start="2017-01-01", end="2017-01-04", inclusive="right") 

2713 DatetimeIndex(['2017-01-02', '2017-01-03', '2017-01-04'], 

2714 dtype='datetime64[us]', freq='D') 

2715 

2716 **Specify a unit** 

2717 

2718 >>> pd.date_range(start="2017-01-01", periods=10, freq="100YS", unit="s") 

2719 DatetimeIndex(['2017-01-01', '2117-01-01', '2217-01-01', '2317-01-01', 

2720 '2417-01-01', '2517-01-01', '2617-01-01', '2717-01-01', 

2721 '2817-01-01', '2917-01-01'], 

2722 dtype='datetime64[s]', freq='100YS-JAN') 

2723 """ 

2724 if freq is None and com.any_none(periods, start, end): 

2725 freq = "D" 

2726 if freq is not None: 

2727 freq = to_offset(freq) 

2728 

2729 if start is NaT or end is NaT: 

2730 # This check needs to come before the `unit = start.unit` line below 

2731 raise ValueError("Neither `start` nor `end` can be NaT") 

2732 

2733 if unit is None: 

2734 # Infer the unit based on the inputs 

2735 

2736 if start is not None and end is not None: 

2737 start = Timestamp(start) 

2738 end = Timestamp(end) 

2739 if abbrev_to_npy_unit(start.unit) > abbrev_to_npy_unit(end.unit): 

2740 unit = start.unit 

2741 else: 

2742 unit = end.unit 

2743 elif start is not None: 

2744 start = Timestamp(start) 

2745 unit = start.unit 

2746 elif end is not None: 

2747 end = Timestamp(end) 

2748 unit = end.unit 

2749 else: 

2750 raise ValueError( 

2751 "Of the four parameters: start, end, periods, " 

2752 "and freq, exactly three must be specified" 

2753 ) 

2754 

2755 # Last we need to watch out for cases where the 'freq' implies a higher 

2756 # unit than either start or end 

2757 if freq is not None: 

2758 creso = abbrev_to_npy_unit(unit) 

2759 if isinstance(freq, Tick): 

2760 if freq._creso > creso: 

2761 unit = freq.base.freqstr # type: ignore[assignment] 

2762 elif hasattr(freq, "offset") and freq.offset is not None: 

2763 # e.g. BDay with an offset 

2764 td = Timedelta(freq.offset) 

2765 if abbrev_to_npy_unit(td.unit) > creso: 

2766 unit = td.unit 

2767 elif type(freq) is DateOffset: 

2768 if getattr(freq, "nanoseconds", 0) != 0: 

2769 # e.g. test_freq_dateoffset_with_relateivedelta_nanos 

2770 unit = "ns" 

2771 elif getattr(freq, "microseconds", 0) != 0 and unit != "ns": 

2772 unit = "us" 

2773 elif getattr(freq, "milliseconds", 0) != 0 and unit not in ["ns", "us"]: 

2774 unit = "ms" 

2775 

2776 dtarr = DatetimeArray._generate_range( 

2777 start=start, 

2778 end=end, 

2779 periods=periods, 

2780 freq=freq, 

2781 tz=tz, 

2782 normalize=normalize, 

2783 ambiguous=ambiguous, 

2784 nonexistent=nonexistent, 

2785 inclusive=inclusive, 

2786 unit=unit, 

2787 **kwargs, 

2788 ) 

2789 result = DatetimeIndex._simple_new(dtarr, name=name) 

2790 result._freq = freq 

2791 return result 

2792 

2793 

2794@set_module("pandas") 

2795def bdate_range( 

2796 start=None, 

2797 end=None, 

2798 periods: int | None = None, 

2799 freq: Frequency | dt.timedelta = "B", 

2800 tz=None, 

2801 normalize: bool = True, 

2802 name: Hashable | None = None, 

2803 weekmask=None, 

2804 holidays=None, 

2805 inclusive: IntervalClosedType = "both", 

2806 **kwargs, 

2807) -> DatetimeIndex: 

2808 """ 

2809 Return a fixed frequency DatetimeIndex with business day as the default. 

2810 

2811 This function generates a DatetimeIndex using business day frequency by 

2812 default, skipping weekends. Custom business day calendars can be 

2813 specified via ``weekmask`` and ``holidays``. 

2814 

2815 Parameters 

2816 ---------- 

2817 start : str or datetime-like, default None 

2818 Left bound for generating dates. 

2819 end : str or datetime-like, default None 

2820 Right bound for generating dates. 

2821 periods : int, default None 

2822 Number of periods to generate. 

2823 freq : str, Timedelta, datetime.timedelta, or DateOffset, default 'B' 

2824 Frequency strings can have multiples, e.g. '5h'. The default is 

2825 business daily ('B'). 

2826 tz : str or None 

2827 Time zone name for returning localized DatetimeIndex, for example 

2828 Asia/Beijing. 

2829 normalize : bool, default False 

2830 Normalize start/end dates to midnight before generating date range. 

2831 name : Hashable, default None 

2832 Name of the resulting DatetimeIndex. 

2833 weekmask : str or None, default None 

2834 Weekmask of valid business days, passed to ``numpy.busdaycalendar``, 

2835 only used when custom frequency strings are passed. The default 

2836 value None is equivalent to 'Mon Tue Wed Thu Fri'. 

2837 holidays : list-like or None, default None 

2838 Dates to exclude from the set of valid business days, passed to 

2839 ``numpy.busdaycalendar``, only used when custom frequency strings 

2840 are passed. 

2841 inclusive : {"both", "neither", "left", "right"}, default "both" 

2842 Include boundaries; Whether to set each bound as closed or open. 

2843 **kwargs 

2844 For compatibility. Has no effect on the result. 

2845 

2846 Returns 

2847 ------- 

2848 DatetimeIndex 

2849 Fixed frequency DatetimeIndex. 

2850 

2851 See Also 

2852 -------- 

2853 date_range : Return a fixed frequency DatetimeIndex. 

2854 period_range : Return a fixed frequency PeriodIndex. 

2855 timedelta_range : Return a fixed frequency TimedeltaIndex. 

2856 

2857 Notes 

2858 ----- 

2859 Of the four parameters: ``start``, ``end``, ``periods``, and ``freq``, 

2860 exactly three must be specified. Specifying ``freq`` is a requirement 

2861 for ``bdate_range``. Use ``date_range`` if specifying ``freq`` is not 

2862 desired. 

2863 

2864 To learn more about the frequency strings, please see 

2865 :ref:`this link<timeseries.offset_aliases>`. 

2866 

2867 Examples 

2868 -------- 

2869 Note how the two weekend days are skipped in the result. 

2870 

2871 >>> pd.bdate_range(start="1/1/2018", end="1/08/2018") 

2872 DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04', 

2873 '2018-01-05', '2018-01-08'], 

2874 dtype='datetime64[us]', freq='B') 

2875 """ 

2876 if freq is None: 

2877 msg = "freq must be specified for bdate_range; use date_range instead" 

2878 raise TypeError(msg) 

2879 

2880 if isinstance(freq, str) and freq.upper().startswith("C"): 

2881 msg = f"invalid custom frequency string: {freq}" 

2882 if freq == "CBH": 

2883 # GH#62849 

2884 raise ValueError(f"{msg}, did you mean cbh?") 

2885 try: 

2886 weekmask = weekmask or "Mon Tue Wed Thu Fri" 

2887 freq = prefix_mapping[freq](holidays=holidays, weekmask=weekmask) 

2888 except (KeyError, TypeError) as err: 

2889 raise ValueError(msg) from err 

2890 elif holidays or weekmask: 

2891 msg = ( 

2892 "a custom frequency string is required when holidays or " 

2893 f"weekmask are passed, got frequency {freq}" 

2894 ) 

2895 raise ValueError(msg) 

2896 

2897 return date_range( 

2898 start=start, 

2899 end=end, 

2900 periods=periods, 

2901 freq=freq, 

2902 tz=tz, 

2903 normalize=normalize, 

2904 name=name, 

2905 inclusive=inclusive, 

2906 **kwargs, 

2907 ) 

2908 

2909 

2910def _time_to_micros(time_obj: dt.time) -> int: 

2911 seconds = time_obj.hour * 60 * 60 + 60 * time_obj.minute + time_obj.second 

2912 return 1_000_000 * seconds + time_obj.microsecond