@@ -16,14 +16,11 @@ use crate::{
1616 parsed_intermediates:: ParsedDate ,
1717 parsers:: { FormattableCalendar , FormattableDate , FormattableYearMonth } ,
1818 provider:: { NeverProvider , TimeZoneProvider } ,
19- temporal_assert,
2019 unix_time:: EpochNanoseconds ,
21- Calendar , MonthCode , TemporalError , TemporalResult , TemporalUnwrap , TimeZone ,
20+ Calendar , MonthCode , TemporalError , TemporalResult , TimeZone ,
2221} ;
2322
24- use super :: {
25- duration:: normalized:: InternalDurationRecord , DateDuration , Duration , PlainDate , PlainDateTime ,
26- } ;
23+ use super :: { duration:: normalized:: InternalDurationRecord , Duration , PlainDate , PlainDateTime } ;
2724use writeable:: Writeable ;
2825
2926/// A partial PlainYearMonth record
@@ -191,70 +188,51 @@ impl PlainYearMonth {
191188 // NOTE: The following operation has been moved to the caller.
192189 // MOVE: 2. If operation is subtract, set duration to CreateNegatedTemporalDuration(duration).
193190
191+ // 3. Let internalDuration be ToInternalDurationRecord(duration).
192+ let internal_duration = duration. to_internal_duration_record ( ) ;
193+
194+ // 4. Let durationToAdd be internalDuration.[[Date]].
195+ let duration_to_add = internal_duration. date ( ) ;
196+
194197 // NOTE: The following are engine specific:
195- // SKIP: 3 . Let resolvedOptions be ? GetOptionsObject(options).
196- // SKIP: 4 . Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
198+ // SKIP: 5 . Let resolvedOptions be ? GetOptionsObject(options).
199+ // SKIP: 6 . Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
197200
198- // 5. Let sign be DurationSign(duration).
199- let sign = duration. sign ( ) ;
201+ // 7. If durationToAdd.[[Weeks]] ≠ 0, or durationToAdd.[[Days]] ≠ 0, or internalDuration.[[Time]] ≠ 0,
202+ // throw a RangeError exception.
203+
204+ if duration_to_add. weeks != 0
205+ || duration_to_add. days != 0
206+ || internal_duration. normalized_time_duration ( ) . 0 != 0
207+ {
208+ return Err ( TemporalError :: range ( )
209+ . with_message ( "Can only add years or months to PlainYearMonth." ) ) ;
210+ }
200211
201- // 6 . Let calendar be yearMonth.[[Calendar]].
212+ // 8 . Let calendar be yearMonth.[[Calendar]].
202213 let calendar = self . calendar ( ) ;
203214
204- // 7 . Let fields be ISODateToFields(calendar, yearMonth.[[ISODate]], year-month).
215+ // 9 . Let fields be ISODateToFields(calendar, yearMonth.[[ISODate]], year-month).
205216 let fields = CalendarFields :: from ( YearMonthCalendarFields :: try_from_year_month ( self ) ?) ;
206217
207- // 8 . Set fields.[[Day]] to 1.
218+ // 10 . Set fields.[[Day]] to 1.
208219 let fields = fields. with_day ( 1 ) ;
209220
210- // 9. Let intermediateDate be ? CalendarDateFromFields(calendar, fields, constrain).
211- let intermediate_date = calendar. date_from_fields ( fields, overflow) ?;
212-
213- // 10. If sign < 0, then
214- let date = if sign. as_sign_multiplier ( ) < 0 {
215- // a. Let oneMonthDuration be ! CreateDateDurationRecord(0, 1, 0, 0).
216- let one_month_duration = DateDuration :: new_unchecked ( 0 , 1 , 0 , 0 ) ;
217-
218- // b. Let nextMonth be ? CalendarDateAdd(calendar, intermediateDate, oneMonthDuration, constrain).
219- let next_month = calendar. date_add (
220- & intermediate_date. iso ,
221- & one_month_duration,
222- Overflow :: Constrain ,
223- ) ?;
224- let next_month = next_month. iso ;
225-
226- // c. Let date be BalanceISODate(nextMonth.[[Year]], nextMonth.[[Month]], nextMonth.[[Day]] - 1).
227- let date = IsoDate :: balance (
228- next_month. year ,
229- i32:: from ( next_month. month ) ,
230- i32:: from ( next_month. day ) . checked_sub ( 1 ) . temporal_unwrap ( ) ?,
231- ) ;
232-
233- // d. Assert: ISODateWithinLimits(date) is true.
234- temporal_assert ! ( date. is_valid( ) ) ;
235-
236- date
237- } else {
238- // 11. Else,
239- // a. Let date be intermediateDate.
240- intermediate_date. iso
241- } ;
242-
243- // 12. Let durationToAdd be ToDateDurationRecordWithoutTime(duration).
244- let duration_to_add = duration. to_date_duration_record_without_time ( ) ?;
221+ // 11. Let date be ? CalendarDateFromFields(calendar, fields, constrain).
222+ let date = calendar. date_from_fields ( fields, Overflow :: Constrain ) ?;
245223
246- // 13 . Let addedDate be ? CalendarDateAdd(calendar, date, durationToAdd, overflow).
247- let added_date = calendar. date_add ( & date, & duration_to_add, overflow) ?;
224+ // 12 . Let addedDate be ? CalendarDateAdd(calendar, date, durationToAdd, overflow).
225+ let added_date = calendar. date_add ( & date. iso , & duration_to_add, overflow) ?;
248226
249- // 14 . Let addedDateFields be ISODateToFields(calendar, addedDate, year-month).
227+ // 13 . Let addedDateFields be ISODateToFields(calendar, addedDate, year-month).
250228 let added_date_fields = YearMonthCalendarFields :: new ( )
251229 . with_month_code ( added_date. month_code ( ) )
252230 . with_year ( added_date. year ( ) ) ;
253231
254- // 15 . Let isoDate be ? CalendarYearMonthFromFields(calendar, addedDateFields, overflow).
232+ // 14 . Let isoDate be ? CalendarYearMonthFromFields(calendar, addedDateFields, overflow).
255233 let iso_date = calendar. year_month_from_fields ( added_date_fields, overflow) ?;
256234
257- // 16 . Return ! CreateTemporalYearMonth(isoDate, calendar).
235+ // 15 . Return ! CreateTemporalYearMonth(isoDate, calendar).
258236 Ok ( iso_date)
259237 }
260238
@@ -1172,4 +1150,18 @@ mod tests {
11721150 "2001-12-15[u-ca=chinese]"
11731151 ) ;
11741152 }
1153+
1154+ #[ test]
1155+ /// Should be able to subtract years from a leap month
1156+ ///
1157+ /// Regression test for bugs fixed by <https://github.com/tc39/proposal-temporal/pull/3253/>
1158+ fn test_subtract_years_from_leap_month ( ) {
1159+ let dangi_m03l_2012 = PlainYearMonth :: from_str ( "2012-04-21[u-ca=dangi]" ) . unwrap ( ) ;
1160+ let minus_19y = Duration :: from_str ( "-P19Y" ) . unwrap ( ) ;
1161+ let prev = dangi_m03l_2012. add ( & minus_19y, Overflow :: Reject ) . unwrap ( ) ;
1162+ assert_eq ! (
1163+ prev. to_ixdtf_string( Default :: default ( ) ) ,
1164+ "1993-04-22[u-ca=dangi]"
1165+ ) ;
1166+ }
11751167}
0 commit comments