42
42
from __future__ import annotations
43
43
44
44
import math
45
- import warnings
46
45
from datetime import timedelta
47
- from typing import TYPE_CHECKING , Any
46
+ from typing import TYPE_CHECKING , Any , Optional
48
47
49
48
import numpy as np
50
49
import pandas as pd
58
57
)
59
58
from xarray .core .common import _contains_cftime_datetimes
60
59
from xarray .core .options import OPTIONS
61
- from xarray .core .utils import attempt_import , is_scalar
60
+ from xarray .core .types import PDDatetimeUnitOptions
61
+ from xarray .core .utils import attempt_import , emit_user_level_warning , is_scalar
62
62
63
63
if TYPE_CHECKING :
64
64
from xarray .coding .cftime_offsets import BaseCFTimeOffset
@@ -239,6 +239,8 @@ class CFTimeIndex(pd.Index):
239
239
cftime_range
240
240
"""
241
241
242
+ _data : np .ndarray
243
+
242
244
year = _field_accessor ("year" , "The year of the datetime" )
243
245
month = _field_accessor ("month" , "The month of the datetime" )
244
246
day = _field_accessor ("day" , "The days of the datetime" )
@@ -544,14 +546,18 @@ def __rsub__(self, other):
544
546
"that can be expressed at the nanosecond resolution."
545
547
) from err
546
548
547
- def to_datetimeindex (self , unsafe = False ):
549
+ def to_datetimeindex (
550
+ self , unsafe : bool = False , time_unit : Optional [PDDatetimeUnitOptions ] = None
551
+ ) -> pd .DatetimeIndex :
548
552
"""If possible, convert this index to a pandas.DatetimeIndex.
549
553
550
554
Parameters
551
555
----------
552
556
unsafe : bool
553
- Flag to turn off warning when converting from a CFTimeIndex with
554
- a non-standard calendar to a DatetimeIndex (default ``False``).
557
+ Flag to turn off calendar mismatch warnings (default ``False``).
558
+ time_unit : str
559
+ Time resolution of resulting DatetimeIndex. Can be one of `"s"`,
560
+ ``"ms"``, ``"us"``, or ``"ns"`` (default ``"ns"``).
555
561
556
562
Returns
557
563
-------
@@ -561,45 +567,68 @@ def to_datetimeindex(self, unsafe=False):
561
567
------
562
568
ValueError
563
569
If the CFTimeIndex contains dates that are not possible in the
564
- standard calendar or outside the nanosecond-precision range.
570
+ standard calendar or outside the range representable by the
571
+ specified ``time_unit``.
565
572
566
573
Warns
567
574
-----
568
575
RuntimeWarning
569
- If converting from a non-standard calendar to a DatetimeIndex.
576
+ If converting from a non-standard calendar, or a Gregorian
577
+ calendar with dates prior to the reform (1582-10-15).
570
578
571
579
Warnings
572
580
--------
573
- Note that for non-standard calendars, this will change the calendar
574
- type of the index. In that case the result of this method should be
575
- used with caution.
581
+ Note that for non-proleptic Gregorian calendars, this will change the
582
+ calendar type of the index. In that case the result of this method
583
+ should be used with caution.
576
584
577
585
Examples
578
586
--------
579
587
>>> times = xr.cftime_range("2000", periods=2, calendar="gregorian")
580
588
>>> times
581
589
CFTimeIndex([2000-01-01 00:00:00, 2000-01-02 00:00:00],
582
590
dtype='object', length=2, calendar='standard', freq=None)
583
- >>> times.to_datetimeindex()
584
- DatetimeIndex(['2000-01-01', '2000-01-02'], dtype='datetime64[us ]', freq=None)
591
+ >>> times.to_datetimeindex(time_unit="ns" )
592
+ DatetimeIndex(['2000-01-01', '2000-01-02'], dtype='datetime64[ns ]', freq=None)
585
593
"""
586
594
587
595
if not self ._data .size :
588
596
return pd .DatetimeIndex ([])
589
597
590
- # transform to us-resolution is needed for DatetimeIndex
591
- nptimes = cftime_to_nptime (self , time_unit = "us" )
598
+ if time_unit is None :
599
+ emit_user_level_warning (
600
+ "In a future version of xarray to_datetimeindex will default "
601
+ "to returning a 'us'-resolution DatetimeIndex instead of a "
602
+ "'ns'-resolution DatetimeIndex. This warning can be silenced "
603
+ "by explicitly setting the time_unit of the index returned." ,
604
+ FutureWarning ,
605
+ )
606
+ time_unit = "ns"
607
+
608
+ nptimes = cftime_to_nptime (self , time_unit = time_unit )
592
609
calendar = infer_calendar_name (self )
593
610
if calendar not in _STANDARD_CALENDARS and not unsafe :
594
- warnings . warn (
611
+ emit_user_level_warning (
595
612
"Converting a CFTimeIndex with dates from a non-standard "
596
- f"calendar, { calendar !r} , to a pandas.DatetimeIndex, which uses dates "
597
- "from the standard calendar. This may lead to subtle errors "
598
- "in operations that depend on the length of time between "
599
- "dates." ,
613
+ f"calendar, { calendar !r} , to a pandas.DatetimeIndex, which "
614
+ "uses dates from the standard calendar. This may lead to "
615
+ "subtle errors in operations that depend on the length of "
616
+ "time between dates." ,
600
617
RuntimeWarning ,
601
- stacklevel = 2 ,
602
618
)
619
+ if calendar == "standard" and not unsafe :
620
+ reform_date = self .date_type (1582 , 10 , 15 )
621
+ if self .min () < reform_date :
622
+ emit_user_level_warning (
623
+ "Converting a CFTimeIndex with dates from a Gregorian "
624
+ "calendar that fall before the reform date of 1582-10-15 "
625
+ "to a pandas.DatetimeIndex. During this time period the "
626
+ "Gregorian calendar and the proleptic Gregorian calendar "
627
+ "of the DatetimeIndex do not exactly align. This warning "
628
+ "can be silenced by setting unsafe=True." ,
629
+ RuntimeWarning ,
630
+ )
631
+
603
632
return pd .DatetimeIndex (nptimes )
604
633
605
634
def strftime (self , date_format ):
0 commit comments