Skip to content

Commit 926963b

Browse files
ptomato12wrigja
authored andcommitted
Refactor add/subtract to match spec
Introduces the DRY operations ES.AddDurationToOrSubtractDurationFrom___ in order to match recent changes to the spec text. UPSTREAM_COMMIT=7671bd28cc9b18ce943be78dc343cca14b1858c1
1 parent 8c480a4 commit 926963b

File tree

7 files changed

+235
-339
lines changed

7 files changed

+235
-339
lines changed

lib/duration.ts

Lines changed: 4 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -189,67 +189,13 @@ export class Duration implements Temporal.Duration {
189189
Math.abs(GetSlot(this, NANOSECONDS))
190190
);
191191
}
192-
add(other: Params['add'][0], optionsParam: Params['add'][1] = undefined) {
192+
add(other: Params['add'][0], options: Params['add'][1] = undefined): Return['add'] {
193193
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
194-
let { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } =
195-
ES.ToTemporalDurationRecord(other);
196-
const options = ES.GetOptionsObject(optionsParam);
197-
const relativeTo = ES.ToRelativeTemporalObject(options);
198-
({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.AddDuration(
199-
GetSlot(this, YEARS),
200-
GetSlot(this, MONTHS),
201-
GetSlot(this, WEEKS),
202-
GetSlot(this, DAYS),
203-
GetSlot(this, HOURS),
204-
GetSlot(this, MINUTES),
205-
GetSlot(this, SECONDS),
206-
GetSlot(this, MILLISECONDS),
207-
GetSlot(this, MICROSECONDS),
208-
GetSlot(this, NANOSECONDS),
209-
years,
210-
months,
211-
weeks,
212-
days,
213-
hours,
214-
minutes,
215-
seconds,
216-
milliseconds,
217-
microseconds,
218-
nanoseconds,
219-
relativeTo
220-
));
221-
return new Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds);
194+
return ES.AddDurationToOrSubtractDurationFromDuration('add', this, other, options);
222195
}
223-
subtract(other: Params['subtract'][0], optionsParam: Params['subtract'][1] = undefined) {
196+
subtract(other: Params['subtract'][0], options: Params['subtract'][1] = undefined): Return['subtract'] {
224197
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
225-
let { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } =
226-
ES.ToTemporalDurationRecord(other);
227-
const options = ES.GetOptionsObject(optionsParam);
228-
const relativeTo = ES.ToRelativeTemporalObject(options);
229-
({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.AddDuration(
230-
GetSlot(this, YEARS),
231-
GetSlot(this, MONTHS),
232-
GetSlot(this, WEEKS),
233-
GetSlot(this, DAYS),
234-
GetSlot(this, HOURS),
235-
GetSlot(this, MINUTES),
236-
GetSlot(this, SECONDS),
237-
GetSlot(this, MILLISECONDS),
238-
GetSlot(this, MICROSECONDS),
239-
GetSlot(this, NANOSECONDS),
240-
-years,
241-
-months,
242-
-weeks,
243-
-days,
244-
-hours,
245-
-minutes,
246-
-seconds,
247-
-milliseconds,
248-
-microseconds,
249-
-nanoseconds,
250-
relativeTo
251-
));
252-
return new Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds);
198+
return ES.AddDurationToOrSubtractDurationFromDuration('subtract', this, other, options);
253199
}
254200
round(optionsParam: Params['round'][0]): Return['round'] {
255201
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');

lib/ecmascript.ts

Lines changed: 215 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ export function ToIntegerThrowOnInfinity(value: unknown): number {
160160
return integer;
161161
}
162162

163-
export function ToPositiveInteger(valueParam: unknown, property?: string): number {
163+
function ToPositiveInteger(valueParam: unknown, property?: string): number {
164164
const value = ToInteger(valueParam);
165165
if (!NumberIsFinite(value)) {
166166
throw new RangeError('infinity is out of range');
@@ -710,7 +710,7 @@ function DurationHandleFractions(
710710
return { minutes, seconds, milliseconds, microseconds, nanoseconds };
711711
}
712712

713-
export function ToTemporalDurationRecord(item: Temporal.DurationLike | string) {
713+
function ToTemporalDurationRecord(item: Temporal.DurationLike | string) {
714714
if (!IsObject(item)) {
715715
return ParseTemporalDurationString(ToString(item));
716716
}
@@ -757,7 +757,7 @@ export function ToTemporalDurationRecord(item: Temporal.DurationLike | string) {
757757
return { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds };
758758
}
759759

760-
export function ToLimitedTemporalDuration(
760+
function ToLimitedTemporalDuration(
761761
item: Temporal.DurationLike | string,
762762
disallowedProperties: (keyof Temporal.DurationLike)[]
763763
) {
@@ -4688,7 +4688,7 @@ export function AddISODate(
46884688
return { year, month, day };
46894689
}
46904690

4691-
export function AddTime(
4691+
function AddTime(
46924692
hourParam: number,
46934693
minuteParam: number,
46944694
secondParam: number,
@@ -4727,7 +4727,7 @@ export function AddTime(
47274727
return { deltaDays, hour, minute, second, millisecond, microsecond, nanosecond };
47284728
}
47294729

4730-
export function AddDuration(
4730+
function AddDuration(
47314731
y1: number,
47324732
mon1: number,
47334733
w1: number,
@@ -4863,15 +4863,7 @@ export function AddDuration(
48634863
return { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds };
48644864
}
48654865

4866-
export function AddInstant(
4867-
epochNanoseconds: JSBI,
4868-
h: number,
4869-
min: number,
4870-
s: number,
4871-
ms: number,
4872-
µs: number,
4873-
ns: number
4874-
) {
4866+
function AddInstant(epochNanoseconds: JSBI, h: number, min: number, s: number, ms: number, µs: number, ns: number) {
48754867
let sum = ZERO;
48764868
sum = JSBI.add(sum, JSBI.BigInt(ns));
48774869
sum = JSBI.add(sum, JSBI.multiply(JSBI.BigInt(µs), THOUSAND));
@@ -4885,7 +4877,7 @@ export function AddInstant(
48854877
return result;
48864878
}
48874879

4888-
export function AddDateTime(
4880+
function AddDateTime(
48894881
year: number,
48904882
month: number,
48914883
day: number,
@@ -4999,6 +4991,214 @@ export function AddZonedDateTime(
49994991
return AddInstant(GetSlot(instantIntermediate, EPOCHNANOSECONDS), h, min, s, ms, µs, ns);
50004992
}
50014993

4994+
type AddSubtractOperation = 'add' | 'subtract';
4995+
4996+
export function AddDurationToOrSubtractDurationFromDuration(
4997+
operation: AddSubtractOperation,
4998+
duration: Temporal.Duration,
4999+
other: DurationParams['add'][0],
5000+
optionsParam: DurationParams['add'][1]
5001+
): Temporal.Duration {
5002+
const sign = operation === 'subtract' ? -1 : 1;
5003+
let { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } =
5004+
ToTemporalDurationRecord(other);
5005+
const options = GetOptionsObject(optionsParam);
5006+
const relativeTo = ToRelativeTemporalObject(options);
5007+
({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = AddDuration(
5008+
GetSlot(duration, YEARS),
5009+
GetSlot(duration, MONTHS),
5010+
GetSlot(duration, WEEKS),
5011+
GetSlot(duration, DAYS),
5012+
GetSlot(duration, HOURS),
5013+
GetSlot(duration, MINUTES),
5014+
GetSlot(duration, SECONDS),
5015+
GetSlot(duration, MILLISECONDS),
5016+
GetSlot(duration, MICROSECONDS),
5017+
GetSlot(duration, NANOSECONDS),
5018+
sign * years,
5019+
sign * months,
5020+
sign * weeks,
5021+
sign * days,
5022+
sign * hours,
5023+
sign * minutes,
5024+
sign * seconds,
5025+
sign * milliseconds,
5026+
sign * microseconds,
5027+
sign * nanoseconds,
5028+
relativeTo
5029+
));
5030+
const Duration = GetIntrinsic('%Temporal.Duration%');
5031+
return new Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds);
5032+
}
5033+
5034+
export function AddDurationToOrSubtractDurationFromInstant(
5035+
operation: AddSubtractOperation,
5036+
instant: Temporal.Instant,
5037+
durationLike: InstantParams['add'][0]
5038+
): Temporal.Instant {
5039+
const sign = operation === 'subtract' ? -1 : 1;
5040+
const { hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ToLimitedTemporalDuration(durationLike, [
5041+
'years',
5042+
'months',
5043+
'weeks',
5044+
'days'
5045+
]);
5046+
const ns = AddInstant(
5047+
GetSlot(instant, EPOCHNANOSECONDS),
5048+
sign * hours,
5049+
sign * minutes,
5050+
sign * seconds,
5051+
sign * milliseconds,
5052+
sign * microseconds,
5053+
sign * nanoseconds
5054+
);
5055+
const Instant = GetIntrinsic('%Temporal.Instant%');
5056+
return new Instant(ns);
5057+
}
5058+
5059+
export function AddDurationToOrSubtractDurationFromPlainDateTime(
5060+
operation: AddSubtractOperation,
5061+
dateTime: Temporal.PlainDateTime,
5062+
durationLike: PlainDateTimeParams['add'][0],
5063+
optionsParam: PlainDateTimeParams['add'][1]
5064+
): Temporal.PlainDateTime {
5065+
const sign = operation === 'subtract' ? -1 : 1;
5066+
const { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } =
5067+
ToTemporalDurationRecord(durationLike);
5068+
const options = GetOptionsObject(optionsParam);
5069+
const calendar = GetSlot(dateTime, CALENDAR);
5070+
const { year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = AddDateTime(
5071+
GetSlot(dateTime, ISO_YEAR),
5072+
GetSlot(dateTime, ISO_MONTH),
5073+
GetSlot(dateTime, ISO_DAY),
5074+
GetSlot(dateTime, ISO_HOUR),
5075+
GetSlot(dateTime, ISO_MINUTE),
5076+
GetSlot(dateTime, ISO_SECOND),
5077+
GetSlot(dateTime, ISO_MILLISECOND),
5078+
GetSlot(dateTime, ISO_MICROSECOND),
5079+
GetSlot(dateTime, ISO_NANOSECOND),
5080+
calendar,
5081+
sign * years,
5082+
sign * months,
5083+
sign * weeks,
5084+
sign * days,
5085+
sign * hours,
5086+
sign * minutes,
5087+
sign * seconds,
5088+
sign * milliseconds,
5089+
sign * microseconds,
5090+
sign * nanoseconds,
5091+
options
5092+
);
5093+
return CreateTemporalDateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar);
5094+
}
5095+
5096+
export function AddDurationToOrSubtractDurationFromPlainTime(
5097+
operation: AddSubtractOperation,
5098+
temporalTime: Temporal.PlainTime,
5099+
durationLike: PlainTimeParams['add'][0]
5100+
): Temporal.PlainTime {
5101+
const sign = operation === 'subtract' ? -1 : 1;
5102+
const { hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ToTemporalDurationRecord(durationLike);
5103+
let { hour, minute, second, millisecond, microsecond, nanosecond } = AddTime(
5104+
GetSlot(temporalTime, ISO_HOUR),
5105+
GetSlot(temporalTime, ISO_MINUTE),
5106+
GetSlot(temporalTime, ISO_SECOND),
5107+
GetSlot(temporalTime, ISO_MILLISECOND),
5108+
GetSlot(temporalTime, ISO_MICROSECOND),
5109+
GetSlot(temporalTime, ISO_NANOSECOND),
5110+
sign * hours,
5111+
sign * minutes,
5112+
sign * seconds,
5113+
sign * milliseconds,
5114+
sign * microseconds,
5115+
sign * nanoseconds
5116+
);
5117+
({ hour, minute, second, millisecond, microsecond, nanosecond } = RegulateTime(
5118+
hour,
5119+
minute,
5120+
second,
5121+
millisecond,
5122+
microsecond,
5123+
nanosecond,
5124+
'reject'
5125+
));
5126+
const PlainTime = GetIntrinsic('%Temporal.PlainTime%');
5127+
return new PlainTime(hour, minute, second, millisecond, microsecond, nanosecond);
5128+
}
5129+
5130+
export function AddDurationToOrSubtractDurationFromPlainYearMonth(
5131+
operation: AddSubtractOperation,
5132+
yearMonth: Temporal.PlainYearMonth,
5133+
durationLike: PlainYearMonthParams['add'][0],
5134+
optionsParam: PlainYearMonthParams['add'][1]
5135+
): Temporal.PlainYearMonth {
5136+
let duration = ToTemporalDurationRecord(durationLike);
5137+
if (operation === 'subtract') {
5138+
duration = {
5139+
years: -duration.years,
5140+
months: -duration.months,
5141+
weeks: -duration.weeks,
5142+
days: -duration.days,
5143+
hours: -duration.hours,
5144+
minutes: -duration.minutes,
5145+
seconds: -duration.seconds,
5146+
milliseconds: -duration.milliseconds,
5147+
microseconds: -duration.microseconds,
5148+
nanoseconds: -duration.nanoseconds
5149+
};
5150+
}
5151+
let { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = duration;
5152+
({ days } = BalanceDuration(days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, 'day'));
5153+
5154+
const options = GetOptionsObject(optionsParam);
5155+
5156+
const calendar = GetSlot(yearMonth, CALENDAR);
5157+
const fieldNames = CalendarFields(calendar, ['monthCode', 'year']) as ReadonlyArray<
5158+
keyof Temporal.PlainYearMonthLike
5159+
>;
5160+
const fields = ToTemporalYearMonthFields(yearMonth, fieldNames);
5161+
const sign = DurationSign(years, months, weeks, days, 0, 0, 0, 0, 0, 0);
5162+
const day = sign < 0 ? ToPositiveInteger(CalendarDaysInMonth(calendar, yearMonth)) : 1;
5163+
const startDate = CalendarDateFromFields(calendar, { ...fields, day });
5164+
const optionsCopy = { ...options };
5165+
const addedDate = CalendarDateAdd(calendar, startDate, { ...duration, days }, options);
5166+
const addedDateFields = ToTemporalYearMonthFields(addedDate, fieldNames);
5167+
5168+
return CalendarYearMonthFromFields(calendar, addedDateFields, optionsCopy);
5169+
}
5170+
5171+
export function AddDurationToOrSubtractDurationFromZonedDateTime(
5172+
operation: AddSubtractOperation,
5173+
zonedDateTime: Temporal.ZonedDateTime,
5174+
durationLike: ZonedDateTimeParams['add'][0],
5175+
optionsParam: ZonedDateTimeParams['add'][1]
5176+
): Temporal.ZonedDateTime {
5177+
const sign = operation === 'subtract' ? -1 : 1;
5178+
const { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } =
5179+
ToTemporalDurationRecord(durationLike);
5180+
const options = GetOptionsObject(optionsParam);
5181+
const timeZone = GetSlot(zonedDateTime, TIME_ZONE);
5182+
const calendar = GetSlot(zonedDateTime, CALENDAR);
5183+
const epochNanoseconds = AddZonedDateTime(
5184+
GetSlot(zonedDateTime, INSTANT),
5185+
timeZone,
5186+
calendar,
5187+
sign * years,
5188+
sign * months,
5189+
sign * weeks,
5190+
sign * days,
5191+
sign * hours,
5192+
sign * minutes,
5193+
sign * seconds,
5194+
sign * milliseconds,
5195+
sign * microseconds,
5196+
sign * nanoseconds,
5197+
options
5198+
);
5199+
return CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar);
5200+
}
5201+
50025202
function RoundNumberToIncrement(quantity: JSBI, increment: number, mode: Temporal.RoundingMode) {
50035203
if (increment === 1) return quantity;
50045204
let { quotient, remainder } = divmod(quantity, JSBI.BigInt(increment));

lib/instant.ts

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -55,37 +55,11 @@ export class Instant implements Temporal.Instant {
5555

5656
add(temporalDurationLike: Params['add'][0]): Return['add'] {
5757
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
58-
const { hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.ToLimitedTemporalDuration(
59-
temporalDurationLike,
60-
['years', 'months', 'weeks', 'days']
61-
);
62-
const ns = ES.AddInstant(
63-
GetSlot(this, EPOCHNANOSECONDS),
64-
hours,
65-
minutes,
66-
seconds,
67-
milliseconds,
68-
microseconds,
69-
nanoseconds
70-
);
71-
return new Instant(ns);
58+
return ES.AddDurationToOrSubtractDurationFromInstant('add', this, temporalDurationLike);
7259
}
7360
subtract(temporalDurationLike: Params['subtract'][0]): Return['subtract'] {
7461
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
75-
const { hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.ToLimitedTemporalDuration(
76-
temporalDurationLike,
77-
['years', 'months', 'weeks', 'days']
78-
);
79-
const ns = ES.AddInstant(
80-
GetSlot(this, EPOCHNANOSECONDS),
81-
-hours,
82-
-minutes,
83-
-seconds,
84-
-milliseconds,
85-
-microseconds,
86-
-nanoseconds
87-
);
88-
return new Instant(ns);
62+
return ES.AddDurationToOrSubtractDurationFromInstant('subtract', this, temporalDurationLike);
8963
}
9064
until(other: Params['until'][0], options: Params['until'][1] = undefined): Return['until'] {
9165
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');

0 commit comments

Comments
 (0)