@@ -475,29 +475,35 @@ def _get_date_part(self, part: str) -> Optional[str]:
475475 def possible_years (self ) -> list [int ] | range :
476476 """A list or range of possible years for this date in the original calendar.
477477 Returns a list with a single year for dates with fully-known years."""
478- if self .known_year :
479- return [self .earliest .year ]
478+ # get the initial value passed in for year in original calendar
479+ initial_year_value = self .initial_values ["year" ]
480+ # if integer, year is fully known and is the only possible value
481+ if isinstance (initial_year_value , int ):
482+ return [initial_year_value ]
480483
481- step = 1
484+ # if year is None or string with all unknown digits, bail out
482485 if (
483- self . is_partially_known ( "year" )
484- and str (self .year ).replace (self .MISSING_DIGIT , "" ) ! = ""
486+ initial_year_value is None
487+ or str (self .year ).replace (self .MISSING_DIGIT , "" ) = = ""
485488 ):
486- # determine the smallest step size for the missing digit
487- earliest_year = int (str (self .year ).replace (self .MISSING_DIGIT , "0" ))
488- latest_year = int (str (self .year ).replace (self .MISSING_DIGIT , "9" ))
489- missing_digit_place = len (str (self .year )) - str (self .year ).rfind (
490- self .MISSING_DIGIT
489+ # otherwise, year is fully unknown
490+ # returning range from min year to max year is not useful in any scenario!
491+ raise ValueError (
492+ "Possible years cannot be returned for completely unknown year"
491493 )
492- # convert place to 1, 10, 100, 1000, etc.
493- step = 10 ** (missing_digit_place - 1 )
494- return range (earliest_year , latest_year + 1 , step )
495-
496- # otherwise, year is fully unknown
497- # returning range from min year to max year is not useful in any scenario!
498- raise ValueError (
499- "Possible years cannot be returned for completely unknown year"
494+
495+ # otherwise, year is partially known
496+ # determine the smallest step size for the missing digit
497+ earliest_year = int (str (self .year ).replace (self .MISSING_DIGIT , "0" ))
498+ latest_year = int (str (self .year ).replace (self .MISSING_DIGIT , "9" ))
499+ missing_digit_place = len (str (self .year )) - str (self .year ).rfind (
500+ self .MISSING_DIGIT
500501 )
502+ # convert place to 1, 10, 100, 1000, etc.
503+ step = 10 ** (missing_digit_place - 1 )
504+ # generate a range from earliest to latest with the appropriate step
505+ # based on the smallest missing digit
506+ return range (earliest_year , latest_year + 1 , step )
501507
502508 @property
503509 def representative_years (self ) -> list [int ]:
@@ -540,12 +546,32 @@ def duration(self) -> Timedelta | UnDelta:
540546 # appease mypy, which says month values could be None here;
541547 # Date object allows optional month, but earliest/latest initialization
542548 # should always be day-precision dates
543- if self .earliest .month is not None and self .latest .month is not None :
544- for possible_month in range (self .earliest .month , self .latest .month + 1 ):
545- for year in self .representative_years :
546- possible_max_days .add (
547- self .calendar_converter .max_day (year , possible_month )
548- )
549+
550+ # use months from the original calendar, not months from
551+ # earliest/latest dates, which have been converted to Gregorian
552+ initial_month_value = self .initial_values ["month" ]
553+ # if integer, month is fully known and is the only possible value
554+ possible_months : list [int ] | range
555+ if isinstance (initial_month_value , int ):
556+ possible_months = [initial_month_value ]
557+ elif isinstance (initial_month_value , str ):
558+ # determine earliest and latest possible months
559+ # based on missing digits and calendar
560+ year = (
561+ self .year
562+ if isinstance (self .year , int )
563+ else self .calendar_converter .LEAP_YEAR
564+ )
565+ earliest_month , latest_month = self ._missing_digit_minmax (
566+ initial_month_value ,
567+ self .calendar_converter .min_month (),
568+ self .calendar_converter .max_month (year ),
569+ )
570+ possible_months = range (earliest_month , latest_month + 1 )
571+
572+ for month in possible_months :
573+ for year in self .representative_years :
574+ possible_max_days .add (self .calendar_converter .max_day (year , month ))
549575
550576 # if precision is year but year is unknown, return an uncertain delta
551577 elif self .precision == DatePrecision .YEAR :
0 commit comments