( date: CalendarDate | CalendarDateTime, duration: DateTimeDuration )
| 45 | duration: DateTimeDuration |
| 46 | ): CalendarDate | CalendarDateTime; |
| 47 | export function add( |
| 48 | date: CalendarDate | CalendarDateTime, |
| 49 | duration: DateTimeDuration |
| 50 | ): Mutable<AnyCalendarDate | AnyDateTime> { |
| 51 | let mutableDate: Mutable<AnyCalendarDate | AnyDateTime> = date.copy(); |
| 52 | let days = 'hour' in mutableDate ? addTimeFields(mutableDate, duration) : 0; |
| 53 | |
| 54 | addYears(mutableDate, duration.years || 0); |
| 55 | if (mutableDate.calendar.balanceYearMonth) { |
| 56 | mutableDate.calendar.balanceYearMonth(mutableDate, date); |
| 57 | } |
| 58 | |
| 59 | mutableDate.month += duration.months || 0; |
| 60 | |
| 61 | balanceYearMonth(mutableDate); |
| 62 | constrainMonthDay(mutableDate); |
| 63 | |
| 64 | mutableDate.day += (duration.weeks || 0) * 7; |
| 65 | mutableDate.day += duration.days || 0; |
| 66 | mutableDate.day += days; |
| 67 | |
| 68 | balanceDay(mutableDate); |
| 69 | |
| 70 | if (mutableDate.calendar.balanceDate) { |
| 71 | mutableDate.calendar.balanceDate(mutableDate); |
| 72 | } |
| 73 | |
| 74 | // Constrain in case adding ended up with a date outside the valid range for the calendar system. |
| 75 | // The behavior here is slightly different than when constraining in the `set` function in that |
| 76 | // we adjust smaller fields to their minimum/maximum values rather than constraining each field |
| 77 | // individually. This matches the general behavior of `add` vs `set` regarding how fields are balanced. |
| 78 | if (mutableDate.year < 1) { |
| 79 | mutableDate.year = 1; |
| 80 | mutableDate.month = 1; |
| 81 | mutableDate.day = 1; |
| 82 | } |
| 83 | |
| 84 | let maxYear = mutableDate.calendar.getYearsInEra(mutableDate); |
| 85 | if (mutableDate.year > maxYear) { |
| 86 | let isInverseEra = mutableDate.calendar.isInverseEra?.(mutableDate); |
| 87 | mutableDate.year = maxYear; |
| 88 | mutableDate.month = isInverseEra ? 1 : mutableDate.calendar.getMonthsInYear(mutableDate); |
| 89 | mutableDate.day = isInverseEra ? 1 : mutableDate.calendar.getDaysInMonth(mutableDate); |
| 90 | } |
| 91 | |
| 92 | if (mutableDate.month < 1) { |
| 93 | mutableDate.month = 1; |
| 94 | mutableDate.day = 1; |
| 95 | } |
| 96 | |
| 97 | let maxMonth = mutableDate.calendar.getMonthsInYear(mutableDate); |
| 98 | if (mutableDate.month > maxMonth) { |
| 99 | mutableDate.month = maxMonth; |
| 100 | mutableDate.day = mutableDate.calendar.getDaysInMonth(mutableDate); |
| 101 | } |
| 102 | |
| 103 | mutableDate.day = Math.max( |
| 104 | 1, |
no test coverage detected