@@ -1054,21 +1054,40 @@ const nonIsoHelperBase = {
10541054 }
10551055 case 'month' :
10561056 case 'year' : {
1057+ // Sign is -1 if calendarTwo < calendarOne, 1 if calendarTwo > calendarOne
10571058 const sign = this . compareCalendarDates ( calendarTwo , calendarOne ) ;
1059+ // If dates are equal, return 0 date duration
10581060 if ( ! sign ) {
10591061 return { years : 0 , months : 0 , weeks : 0 , days : 0 } ;
10601062 }
1063+ // Take the difference between the years of the two dates
10611064 const diffYears = calendarTwo . year - calendarOne . year ;
1065+ // Take the difference between the days of the two dates
10621066 const diffDays = calendarTwo . day - calendarOne . day ;
1067+ // Get list of additional months, and possibly cycle info
10631068 const monthInfo = monthCodeInfo [ this . id ] ;
10641069 const cycleInfo = monthInfo ? monthInfo . cycleInfo : { years : 1 , months : 12 } ;
1070+ // Compute years difference if necessary
10651071 if ( diffYears && ( largestUnit === 'year' || cycleInfo ) ) {
1072+ // diffInYearSign is the result of comparing the month-day of calendarOne
1073+ // and the month-day of calendarTwo, in the forwards direction
10661074 let diffInYearSign = 0 ;
1075+ // If calendarTwo's month is greater than calendarOne's month,
1076+ // then the years difference should be positive (or negative if sign < 0).
10671077 if ( calendarTwo . monthCode > calendarOne . monthCode ) diffInYearSign = 1 ;
1078+ // If calendarTwo's month is less than calendarOne's month,
1079+ // then the years difference should be negative (or positive if sign < 0).
10681080 if ( calendarTwo . monthCode < calendarOne . monthCode ) diffInYearSign = - 1 ;
1081+ // If the two months are equal, the sign of the years difference should be
1082+ // the sign of the days difference.
10691083 if ( ! diffInYearSign ) diffInYearSign = MathSign ( diffDays ) ;
1070- const isOneFurtherInYear = diffInYearSign * sign < 0 ;
1071- years = isOneFurtherInYear ? diffYears - sign : diffYears ;
1084+ // isCalendarOneFurtherInYear is true iff the ordering of the years
1085+ // doesn't match the ordering of the month/days.
1086+ const isCalendarOneFurtherInYear = diffInYearSign * sign < 0 ;
1087+ // Add either 1 or -1 to years if isCalendarOneFurtherInYear is true.
1088+ // If monthday-two is later in the year than monthday-one, need
1089+ // to correct diffYears because it's gone one too far.
1090+ years = isCalendarOneFurtherInYear ? diffYears - sign : diffYears ;
10721091 }
10731092 // Try to skip ahead as many months as possible for this calendar
10741093 // without adding month by month in a loop
@@ -1079,13 +1098,26 @@ const nonIsoHelperBase = {
10791098 }
10801099 years = 0 ;
10811100 }
1101+
1102+ // intermediate should be a date between calendarOne and calendarTwo,
1103+ // that is within a year of calendarTwo.
10821104 const intermediate =
10831105 years || months ? this . addCalendar ( calendarOne , { years, months } , 'constrain' , cache ) : calendarOne ;
1106+
1107+ // At this point, intermediate could fail to be in between calendarOne and calendarTwo
1108+ // due to leap years.
1109+ // In that case, add or subtract an extra year from years,
1110+ // so that the months can be totaled up correctly.
1111+ if ( this . compareCalendarDates ( intermediate , calendarTwo ) * sign > 0 ) {
1112+ years -= sign ;
1113+ }
1114+
10841115 // Now we have less than one cycle remaining. Add one month at a time
10851116 // until we go over the target, then back up one month and calculate
10861117 // remaining days.
10871118 let current ;
1088- let next = intermediate ;
1119+ // Need to re-add years and months because years might have changed
1120+ let next = years || months ? this . addCalendar ( calendarOne , { years, months } , 'constrain' , cache ) : calendarOne ;
10891121 do {
10901122 months += sign ;
10911123 current = next ;
@@ -1099,6 +1131,10 @@ const nonIsoHelperBase = {
10991131 months -= sign ; // correct for loop above which overshoots by 1
11001132 const remainingDays = this . calendarDaysUntil ( current , calendarTwo , cache ) ;
11011133 days = remainingDays ;
1134+
1135+ // This may return a duration like <P12M11D> that appears to have unbalanced months.
1136+ // But that's fine, because subtracting <P12M11D> from a date may have different
1137+ // results than subtracting <P1Y11D> from the same date, in the presence of leap months.
11021138 break ;
11031139 }
11041140 }
0 commit comments