Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove {disambiguation: 'balance'} in with() and from() of non-Duration types #642

Merged
merged 9 commits into from
Jun 4, 2020
7 changes: 4 additions & 3 deletions docs/cookbook/plusAndRoundToMonthStart.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
* @returns {Temporal.Date} - Beginning of the next month after the delay
*/
function plusAndRoundToMonthStart(date, delayDays) {
const delayedDate = date.plus({ days: delayDays });
const month = delayedDate.month + 1;
return delayedDate.with({ month, day: 1 }, { disambiguation: 'balance' });
return date
.plus({ days: delayDays })
.plus({ months: 1 }) // constrains to end of month if needed, e.g. Jan 31 -> Feb 28
.with({ day: 1 });
}

const oldLaunchDate = Temporal.Date.from('2019-06-01');
Expand Down
22 changes: 8 additions & 14 deletions docs/date.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ All values are given as reckoned in the [ISO 8601 calendar](https://en.wikipedia
Together, `isoYear`, `isoMonth`, and `isoDay` must represent a valid date in that calendar.

The range of allowed values for this type is exactly enough that calling [`getDate()`](./datetime.html#getDate) on any valid `Temporal.DateTime` will succeed.
If `isoYear`, `isoMonth`, and `isoDay` form a date outside of this range, then `constrain` mode will clamp the date to the limit of the allowed range.
Both `balance` and `reject` mode will throw a `RangeError` in this case.
If `isoYear`, `isoMonth`, and `isoDay` form a date outside of this range, then `constrain` mode will clamp the values to the limit of the allowed range, while `reject` mode will throw a `RangeError`..
justingrant marked this conversation as resolved.
Show resolved Hide resolved

> **NOTE**: The `isoMonth` argument ranges from 1 to 12, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).

Expand All @@ -52,7 +51,7 @@ date = new Temporal.Date(2020, 3, 14) // => 2020-03-14
- `options` (optional object): An object with properties representing options for constructing the date.
The following options are recognized:
- `disambiguation` (string): How to deal with out-of-range values in `thing`.
Allowed values are `constrain`, `balance`, and `reject`.
Allowed values are `constrain` and `reject`.
The default is `constrain`.

**Returns:** a new `Temporal.Date` object.
Expand All @@ -67,7 +66,6 @@ If the string isn't valid according to ISO 8601, then a `RangeError` will be thr

The `disambiguation` option works as follows:
- In `constrain` mode (the default), any out-of-range values are clamped to the nearest in-range value.
- In `balance` mode, any out-of-range values are resolved by balancing them with the next highest unit.
- In `reject` mode, the presence of out-of-range values will cause the function to throw a `RangeError`.

> **NOTE**: The allowed values for the `thing.month` property start at 1, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).
Expand All @@ -90,12 +88,6 @@ date = Temporal.Date.from({ year: 2001, month: 13, day: 1 }, { disambiguation: '
// => 2001-12-01
date = Temporal.Date.from({ year: 2001, month: -1, day: 1 }, { disambiguation: 'constrain' })
// => 2001-01-01
date = Temporal.Date.from({ year: 2001, month: 13, day: 1 }, { disambiguation: 'balance' })
// => 2002-01-01
date = Temporal.Date.from({ year: 2001, month: 0, day: 1 }, { disambiguation: 'balance' });
// => 2000-12-01
date = Temporal.Date.from({ year: 2001, month: -1, day: 1 }, { disambiguation: 'balance' })
// => 2000-11-01
date = Temporal.Date.from({ year: 2001, month: 13, day: 1 }, { disambiguation: 'reject' })
// throws
date = Temporal.Date.from({ year: 2001, month: -1, day: 1 }, { disambiguation: 'reject' })
Expand Down Expand Up @@ -243,7 +235,7 @@ date.with({year: 2100}).leapYear // => false
- `options` (optional object): An object with properties representing options for the operation.
The following options are recognized:
- `disambiguation` (string): How to deal with out-of-range values.
Allowed values are `constrain`, `balance`, and `reject`.
Allowed values are `constrain` and `reject`.
The default is `constrain`.

**Returns:** a new `Temporal.Date` object.
Expand All @@ -256,9 +248,11 @@ Since `Temporal.Date` objects are immutable, use this method instead of modifyin

Usage example:
```javascript
date = Temporal.Date.from('2006-08-24');
// What's the first of the following month?
date.with({day: 1, month: date.month + 1}, { disambiguation: 'balance' }) // => 2006-09-01
date = Temporal.Date.from('2006-01-24');
// What's the first day of this month?
date.with({day: 1}); // => 2006-01-01
// What's the last day of the next month?
date.plus({months: 1}).with({day: date.daysInMonth}); // => 2006-02-28
```

### date.**plus**(_duration_: object, _options_?: object) : Temporal.Date
Expand Down
18 changes: 4 additions & 14 deletions docs/datetime.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ Together, `isoYear`, `isoMonth`, and `isoDay` must represent a valid date in tha
> This value will cause the constructor will throw, so if you have to interoperate with times that may contain leap seconds, use `Temporal.DateTime.from()` instead.

The range of allowed values for this type is exactly enough that calling [`inTimeZone()`](./absolute.html#inTimeZone) on any valid `Temporal.Absolute` with any valid `Temporal.TimeZone` will succeed.
If the parameters passed in to this constructor form a date outside of this range, then `constrain` mode will clamp the values to the limit of the allowed range.
Both `balance` and `reject` mode will throw a `RangeError` in this case.
If the parameters passed in to this constructor form a date outside of this range, then `constrain` mode will clamp the values to the limit of the allowed range, while `reject` mode will throw a `RangeError`.

> **NOTE**: The `isoMonth` argument ranges from 1 to 12, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).

Expand All @@ -66,7 +65,7 @@ datetime = new Temporal.DateTime(2020, 3, 14, 13, 37) // => 2020-03-14T13:37
- `options` (optional object): An object with properties representing options for constructing the date and time.
The following options are recognized:
- `disambiguation` (string): How to deal with out-of-range values in `thing`.
Allowed values are `constrain`, `balance`, and `reject`.
Allowed values are `constrain` and `reject`.
The default is `constrain`.

**Returns:** a new `Temporal.DateTime` object.
Expand All @@ -83,11 +82,10 @@ If the string isn't valid according to ISO 8601, then a `RangeError` will be thr

The `disambiguation` option works as follows:
- In `constrain` mode (the default), any out-of-range values are clamped to the nearest in-range value.
- In `balance` mode, any out-of-range values are resolved by balancing them with the next highest unit.
- In `reject` mode, the presence of out-of-range values will cause the function to throw a `RangeError`.

> **NOTE**: Although Temporal does not deal with leap seconds, dates coming from other software may have a `second` value of 60.
> In the default `constrain` disambiguation mode and when parsing an ISO 8601 string, this will be converted to 59, and in `balance` mode, to 00 of the next minute.
> In the default `constrain` disambiguation mode and when parsing an ISO 8601 string, this will be converted to 59.
> In `reject` mode, this function will throw, so if you have to interoperate with times that may contain leap seconds, don't use `reject`.

> **NOTE**: The allowed values for the `thing.month` property start at 1, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).
Expand Down Expand Up @@ -124,14 +122,6 @@ dt = Temporal.DateTime.from({ year: 2001, month: 1, day: 1, hour: 25 }, { disamb
// => 2001-01-01T23:00
dt = Temporal.DateTime.from({ year: 2001, month: 1, day: 1, minute: 60 }, { disambiguation: 'constrain' })
// => 2001-01-01T00:59
dt = Temporal.DateTime.from({ year: 2001, month: 13, day: 1 }, { disambiguation: 'balance' })
// => 2002-01-01T00:00
dt = Temporal.DateTime.from({ year: 2001, month: 0, day: 1 }, { disambiguation: 'balance' });
// => 2000-12-01T00:00
dt = Temporal.DateTime.from({ year: 2001, month: -1, day: 1 }, { disambiguation: 'balance' })
// => 2000-11-01T00:00
dt = Temporal.DateTime.from({ year: 2001, month: 1, day: 1, hour: 25 }, { disambiguation: 'balance' })
// => 2001-01-02T01:00
dt = Temporal.DateTime.from({ year: 2001, month: 1, day: 1, minute: 60 }, { disambiguation: 'constrain' })
// => 2001-01-01T01:00
dt = Temporal.DateTime.from({ year: 2001, month: 13, day: 1 }, { disambiguation: 'reject' })
Expand Down Expand Up @@ -304,7 +294,7 @@ dt.with({year: 2100}).isLeapYear // => false
- `options` (optional object): An object with properties representing options for the operation.
The following options are recognized:
- `disambiguation` (string): How to deal with out-of-range values.
Allowed values are `constrain`, `balance`, and `reject`.
Allowed values are `constrain` and `reject`.
The default is `constrain`.

**Returns:** a new `Temporal.DateTime` object.
Expand Down
12 changes: 2 additions & 10 deletions docs/monthday.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ md = new Temporal.MonthDay(2, 29) // => 02-29
- `options` (optional object): An object with properties representing options for constructing the date.
The following options are recognized:
- `disambiguation` (string): How to deal with out-of-range values in `thing`.
Allowed values are `constrain`, `balance`, and `reject`.
Allowed values are `constrain` and `reject`.
The default is `constrain`.

**Returns:** a new `Temporal.MonthDay` object.
Expand All @@ -65,7 +65,6 @@ If the string isn't valid according to ISO 8601, then a `RangeError` will be thr

The `disambiguation` option works as follows:
- In `constrain` mode (the default), any out-of-range values are clamped to the nearest in-range value.
- In `balance` mode, any out-of-range values are resolved by balancing them with the next highest unit.
- In `reject` mode, the presence of out-of-range values will cause the function to throw a `RangeError`.

> **NOTE**: The allowed values for the `thing.month` property start at 1, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).
Expand All @@ -89,12 +88,6 @@ md = Temporal.MonthDay.from({ month: 13, day: 1 }, { disambiguation: 'constrain'
// => 12-01
md = Temporal.MonthDay.from({ month: -1, day: 1 }, { disambiguation: 'constrain' })
// => 01-01
md = Temporal.MonthDay.from({ month: 13, day: 1 }, { disambiguation: 'balance' })
// => 01-01
md = Temporal.MonthDay.from({ month: 0, day: 1 }, { disambiguation: 'balance' });
// => 12-01
md = Temporal.MonthDay.from({ month: -1, day: 1 }, { disambiguation: 'balance' })
// => 11-01
md = Temporal.MonthDay.from({ month: 13, day: 1 }, { disambiguation: 'reject' })
// throws
md = Temporal.MonthDay.from({ month: -1, day: 1 }, { disambiguation: 'reject' })
Expand Down Expand Up @@ -127,7 +120,7 @@ md.day // => 24
- `options` (optional object): An object with properties representing options for the operation.
The following options are recognized:
- `disambiguation` (string): How to deal with out-of-range values.
Allowed values are `constrain`, `balance`, and `reject`.
Allowed values are `constrain` and `reject`.
The default is `constrain`.

**Returns:** a new `Temporal.MonthDay` object.
Expand All @@ -136,7 +129,6 @@ This method creates a new `Temporal.MonthDay` which is a copy of `monthDay`, but

The disambiguation parameter tells what should happen when out-of-range values are given or when the result would be an invalid month-day combination, such as "June 31":
- In `constrain` mode (the default), any out-of-range values are clamped to the nearest in-range value, so June 31 would become June 30.
- In `balance` mode, an out-of-range value for the day is resolved by balancing them with the next highest unit, so June 31 would become July 1; and an out-of-range value for the month wraps around, so `{month: 13}` would end up as January.
- In `reject` mode, the presence of out-of-range values will cause the constructor to throw a `RangeError`.

> **NOTE:** For the purpose of this method, February is treated as having 29 days, so that it remains possible to construct a `Temporal.MonthDay` for February 29.
Expand Down
16 changes: 5 additions & 11 deletions docs/time.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ time = new Temporal.Time(13, 37) // => 13:37
- `options` (optional object): An object with properties representing options for constructing the time.
The following options are recognized:
- `disambiguation` (optional string): How to deal with out-of-range values of the other parameters.
Allowed values are `constrain`, `balance`, and `reject`.
Allowed values are `constrain` and `reject`.
The default is `constrain`.

**Returns:** a new `Temporal.Time` object.
Expand All @@ -59,11 +59,10 @@ If the string designates a date or a time zone, they will be ignored.

The `disambiguation` option works as follows:
- In `constrain` mode (the default), any out-of-range values are clamped to the nearest in-range value.
- In `balance` mode, any out-of-range values are resolved by balancing them with the next highest unit.
- In `reject` mode, the presence of out-of-range values will cause the function to throw a `RangeError`.

> **NOTE**: Although Temporal does not deal with leap seconds, times coming from other software may have a `second` value of 60.
> In the default `constrain` disambiguation mode, this will be converted to 59, and in `balance` mode, to 00 of the next minute.
> In the default `constrain` disambiguation mode, this will be converted to 59.
> In `reject` mode, the constructor will throw, so if you have to interoperate with times that may contain leap seconds, don't use `reject`.
> However, if parsing an ISO 8601 string with a seconds component of `:60`, then it will always result in a `second` value of 59, in accordance with POSIX.

Expand Down Expand Up @@ -93,10 +92,6 @@ time = Temporal.Time.from({ hour: 15, minute: 60 }, { disambiguation: 'constrain
// => 15:59
time = Temporal.Time.from({ hour: 15, minute: -1 }, { disambiguation: 'constrain' });
// => 15:00
time = Temporal.Time.from({ hour: 15, minute: 60 }, { disambiguation: 'balance' });
// => 16:00
time = Temporal.Time.from({ hour: 15, minute: -1 }, { disambiguation: 'balance' });
// => 14:59
time = Temporal.Time.from({ hour: 15, minute: 60 }, { disambiguation: 'reject' });
// throws
time = Temporal.Time.from({ hour: 15, minute: -1 }, { disambiguation: 'reject' });
Expand Down Expand Up @@ -163,7 +158,7 @@ time.nanosecond // => 205
- `options` (optional object): An object with properties representing options for the operation.
The following options are recognized:
- `disambiguation` (string): How to deal with out-of-range values.
Allowed values are `constrain`, `balance`, and `reject`.
Allowed values are `constrain` and `reject`.
The default is `constrain`.

**Returns:** a new `Temporal.Time` object.
Expand All @@ -176,14 +171,13 @@ Usage example:
```javascript
time = Temporal.Time.from('19:39:09.068346205');
// What's the top of the next hour?
time.with({
hour: time.hour + 1,
time.plus({hours: 1}).with({
minute: 0,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0
}, { disambiguation: 'balance' }) // => 20:00
}) // => 20:00
```

### time.**plus**(_duration_: object, _options_?: object) : Temporal.Time
Expand Down
11 changes: 2 additions & 9 deletions docs/yearmonth.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ ym = new Temporal.YearMonth(2019, 6) // => 2019-06
- `options` (optional object): An object with properties representing options for constructing the date.
The following options are recognized:
- `disambiguation` (string): How to deal with out-of-range values in `thing`.
Allowed values are `constrain`, `balance`, and `reject`.
Allowed values are `constrain` and `reject`.
The default is `constrain`.

**Returns:** a new `Temporal.YearMonth` object.
Expand All @@ -65,7 +65,6 @@ If the string isn't valid according to ISO 8601, then a `RangeError` will be thr

The `disambiguation` option works as follows:
- In `constrain` mode (the default), any out-of-range values are clamped to the nearest in-range value.
- In `balance` mode, any out-of-range values are resolved by balancing them with the next highest unit.
- In `reject` mode, the presence of out-of-range values will cause the function to throw a `RangeError`.

> **NOTE**: The allowed values for the `thing.month` property start at 1, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).
Expand All @@ -89,12 +88,6 @@ ym = Temporal.YearMonth.from({ year: 2001, month: 13 }, { disambiguation: 'const
// => 2001-12
ym = Temporal.YearMonth.from({ year: 2001, month: -1 }, { disambiguation: 'constrain' })
// => 2001-01
ym = Temporal.YearMonth.from({ year: 2001, month: 13 }, { disambiguation: 'balance' })
// => 2002-01
ym = Temporal.YearMonth.from({ year: 2001, month: 0 }, { disambiguation: 'balance' });
// => 2000-12
ym = Temporal.YearMonth.from({ year: 2001, month: -1 }, { disambiguation: 'balance' })
// => 2000-11
ym = Temporal.YearMonth.from({ year: 2001, month: 13 }, { disambiguation: 'reject' })
// throws
ym = Temporal.YearMonth.from({ year: 2001, month: -1 }, { disambiguation: 'reject' })
Expand Down Expand Up @@ -201,7 +194,7 @@ ym.with({year: 2100}).isLeapYear // => false
- `options` (optional object): An object with properties representing options for the operation.
The following options are recognized:
- `disambiguation` (string): How to deal with out-of-range values.
Allowed values are `constrain`, `balance`, and `reject`.
Allowed values are `constrain` and `reject`.
The default is `constrain`.

**Returns:** a new `Temporal.YearMonth` object.
Expand Down
25 changes: 23 additions & 2 deletions polyfill/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@ export namespace Temporal {
* `from()`.
* */
export type AssignmentOptions = {
/**
* How to deal with out-of-range values
*
* - In `'constrain'` mode, out-of-range values are clamped to the nearest
* in-range value.
* - In `'reject'` mode, out-of-range values will cause the function to
* throw a RangeError.
*
* The default is `'constrain'`.
*/
disambiguation: 'constrain' | 'reject';
};

/**
* Options for assigning fields using `Duration.prototype.with()` or entire
* objects with `Duration.prototype.from()`.
* */
export type DurationAssignmentOptions = {
/**
* How to deal with out-of-range values
*
Expand Down Expand Up @@ -116,7 +134,10 @@ export namespace Temporal {
* See https://tc39.es/proposal-temporal/docs/duration.html for more details.
*/
export class Duration implements Required<DurationLike> {
static from(item: Temporal.Duration | DurationLike | string, options?: AssignmentOptions): Temporal.Duration;
static from(
item: Temporal.Duration | DurationLike | string,
options?: DurationAssignmentOptions
): Temporal.Duration;
constructor(
years?: number,
months?: number,
Expand All @@ -137,7 +158,7 @@ export namespace Temporal {
readonly milliseconds: number;
readonly microseconds: number;
readonly nanoseconds: number;
with(durationLike: DurationLike, options: AssignmentOptions): Temporal.Duration;
with(durationLike: DurationLike, options: DurationAssignmentOptions): Temporal.Duration;
plus(other: Temporal.Duration | DurationLike, options: ArithmeticOptions): Temporal.Duration;
minus(other: Temporal.Duration | DurationLike, options: DurationMinusOptions): Temporal.Duration;
getFields(): Required<DurationLike>;
Expand Down
4 changes: 2 additions & 2 deletions polyfill/lib/date.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class Date {
}
plus(temporalDurationLike, options) {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
const disambiguation = ES.ToArithmeticTemporalDisambiguation(options);
const disambiguation = ES.ToTemporalDisambiguation(options);
const duration = ES.ToLimitedTemporalDuration(temporalDurationLike);
let { year, month, day } = this;
const { years, months, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = duration;
Expand All @@ -101,7 +101,7 @@ export class Date {
}
minus(temporalDurationLike, options) {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
const disambiguation = ES.ToArithmeticTemporalDisambiguation(options);
const disambiguation = ES.ToTemporalDisambiguation(options);
const duration = ES.ToLimitedTemporalDuration(temporalDurationLike);
let { year, month, day } = this;
const { years, months, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = duration;
Expand Down
Loading