Skip to content

Commit

Permalink
Make all the from() operations in the spec more similar
Browse files Browse the repository at this point in the history
Absolute and TimeZone cannot take property bags, so they are different
from the rest, but in general the idea is to call ToX(arg) if Type(arg)
is Object, and XFromString(ToString(arg)) if not.

Reorganize from() to clone the object

Each type's from() method now calls a new abstract operation,
ToFooRecord, which takes a property bag (which can be the actual type)
and returns a Record with the appropriate slots.

If the argument isn't an object, then from() calls ParseFooString
directly. We delete the FooFromString operations, and in most cases the
ToFoo operations unless there is a method somewhere in the API that
actually needs the casting behaviour (including returning the original
object if it's of the correct type.)

Reorganizes the abstract operations in the polyfill to match the
abstract operations in the spec a bit more.

Effectively, this makes Temporal.Foo.from(aFoo) clone the object instead
of returning the same object.

Closes: #232.
  • Loading branch information
Ms2ger committed Apr 1, 2020
1 parent 8af06da commit e02a92c
Show file tree
Hide file tree
Showing 27 changed files with 378 additions and 331 deletions.
10 changes: 5 additions & 5 deletions docs/absolute.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,18 @@ turnOfTheCentury = new Temporal.Absolute(-2208988800000000000n); // => 1900-01-

## Static methods

### Temporal.Absolute.**from**(_thing_: string | Temporal.Absolute) : Temporal.Absolute
### Temporal.Absolute.**from**(_thing_: any) : Temporal.Absolute

**Parameters:**
- `thing` (string or `Temporal.Absolute`): The value representing the desired point in time.
- `thing`: The value representing the desired point in time.

**Returns:** a new `Temporal.Absolute` object (or the same object if `thing` was a `Temporal.Absolute` object.)

This static method creates a new `Temporal.Absolute` object from another value.
If the value is a string, it must be in ISO 8601 format, including a date, a time, and a time zone.
If the value is an object, it must be another `Temporal.Absolute` object, in which case the same object is returned.
If the value is another `Temporal.Absolute` object, the same object is returned.

If `thing` is a string, and the point in time cannot be uniquely determined from the string, then this function throws an exception.
Any other value is converted to a string, which is expected to be in ISO 8601 format, including a date, a time, and a time zone.
If the point in time cannot be uniquely determined from the string, then this function throws an exception.
This includes the case when `thing` is a validly-formatted ISO 8601 string denoting a time that doesn't exist, for example because it was skipped in a daylight saving time transition.

Example usage:
Expand Down
12 changes: 6 additions & 6 deletions docs/date.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ date = new Temporal.Date(2020, 3, 14) // => 2020-03-14

## Static methods

### Temporal.Date.**from**(_thing_: string | object, _options_?: object) : Temporal.Date
### Temporal.Date.**from**(_thing_: any, _options_?: object) : Temporal.Date

**Parameters:**
- `thing` (string or object): The value representing the desired date.
- `thing`: The value representing the desired date.
- `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`.
Expand All @@ -51,13 +51,13 @@ date = new Temporal.Date(2020, 3, 14) // => 2020-03-14
**Returns:** a new `Temporal.Date` object (or the same object if `thing` was a `Temporal.Date` object.)

This static method creates a new `Temporal.Date` object from another value.
If the value is a string, it must be in ISO 8601 format.
Any time or time zone part is optional and will be ignored.
If the string isn't valid according to ISO 8601, then a `RangeError` will be thrown regardless of the value of `disambiguation`.

If the value is another `Temporal.Date` object, the same object is returned.
If the value is any other object, it must have `year`, `month`, and `day` properties, and a `Temporal.Date` will be constructed from them.

Any non-object value is converted to a string, which is expected to be in ISO 8601 format.
Any time or time zone part is optional and will be ignored.
If the string isn't valid according to ISO 8601, then a `RangeError` will be thrown regardless of the value of `disambiguation`.

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.
Expand Down
12 changes: 6 additions & 6 deletions docs/datetime.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ datetime = new Temporal.DateTime(2020, 3, 14, 13, 37) // => 2020-03-14T13:37

## Static methods

### Temporal.DateTime.**from**(_thing_: string | object, _options_?: object) : Temporal.DateTime
### Temporal.DateTime.**from**(_thing_: any, _options_?: object) : Temporal.DateTime

**Parameters:**
- `thing` (string or object): The value representing the desired date and time.
- `thing`: The value representing the desired date and time.
- `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`.
Expand All @@ -61,15 +61,15 @@ datetime = new Temporal.DateTime(2020, 3, 14, 13, 37) // => 2020-03-14T13:37
**Returns:** a new `Temporal.DateTime` object (or the same object if `thing` was a `Temporal.DateTime` object.)

This static method creates a new `Temporal.DateTime` object from another value.
If the value is a string, it must be in ISO 8601 format.
Any time zone part is optional and will be ignored.
If the string isn't valid according to ISO 8601, then a `RangeError` will be thrown regardless of the value of `disambiguation`.

If the value is another `Temporal.DateTime` object, the same object is returned.
If the value is any other object, a `Temporal.DateTime` will be constructed from the values of any `year`, `month`, `day`, `hour`, `minute`, `second`, `millisecond`, `microsecond`, and `nanosecond` properties that are present.
At least the `year`, `month`, and `day` properties must be present.
Any other missing ones will be assumed to be 0.

Any non-object value is converted to a string, which is expected to be in ISO 8601 format.
Any time zone part is optional and will be ignored.
If the string isn't valid according to ISO 8601, then a `RangeError` will be thrown regardless of the value of `disambiguation`.

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.
Expand Down
2 changes: 1 addition & 1 deletion docs/duration.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ new Temporal.Duration() // => PT0S

## Static methods

### Temporal.Duration.**from**(_thing_: string | object, _options_?: object) : Temporal.Duration
### Temporal.Duration.**from**(_thing_: any, _options_?: object) : Temporal.Duration

**Parameters:**
- `thing` (string or object): A `Duration`-like object or a string from which to create a `Temporal.Duration`.
Expand Down
12 changes: 6 additions & 6 deletions docs/monthday.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ md = new Temporal.MonthDay(2, 29) // => 02-29

## Static methods

### Temporal.MonthDay.**from**(_thing_: string | object, _options_?: object) : Temporal.MonthDay
### Temporal.MonthDay.**from**(_thing_: any, _options_?: object) : Temporal.MonthDay

**Parameters:**
- `thing` (string or object): The value representing the desired date.
- `thing`: The value representing the desired date.
- `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`.
Expand All @@ -46,13 +46,13 @@ md = new Temporal.MonthDay(2, 29) // => 02-29
**Returns:** a new `Temporal.MonthDay` object (or the same object if `thing` was a `Temporal.MonthDay` object.)

This static method creates a new `Temporal.MonthDay` object from another value.
If the value is a string, it must be in ISO 8601 format.
Any parts of the string other than the month and the day are optional and will be ignored.
If the string isn't valid according to ISO 8601, then a `RangeError` will be thrown regardless of the value of `disambiguation`.

If the value is another `Temporal.MonthDay` object, the same object is returned.
If the value is any other object, it must have `month` and `day` properties, and a `Temporal.MonthDay` will be constructed from them.

Any non-object value will be converted to a string, which is expected to be in ISO 8601 format.
Any parts of the string other than the month and the day are optional and will be ignored.
If the string isn't valid according to ISO 8601, then a `RangeError` will be thrown regardless of the value of `disambiguation`.

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.
Expand Down
9 changes: 5 additions & 4 deletions docs/time.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ time = new Temporal.Time(13, 37) // => 13:37

## Static methods

### Temporal.Time.**from**(_thing_: string | object, _options_?: object) : Temporal.Time
### Temporal.Time.**from**(_thing_: any, _options_?: object) : Temporal.Time

**Parameters:**
- `thing` (string or object): The value representing the desired time.
- `thing`: The value representing the desired time.
- `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.
Expand All @@ -45,12 +45,13 @@ time = new Temporal.Time(13, 37) // => 13:37
**Returns:** a new `Temporal.Time` object (or the same object if `thing` was a `Temporal.Time` object.)

This static method creates a new `Temporal.Time` object from another value.
If the value is a string, it must be in ISO 8601 format.
If the string designates a date or a time zone, they will be ignored.
If the value is another `Temporal.Time` object, the same object is returned.
If the value is any other object, a `Temporal.Time` will be constructed from the values of any `hour`, `minute`, `second`, `millisecond`, `microsecond`, and `nanosecond` properties that are present.
Any missing ones will be assumed to be 0.

Any non-object value will be converted to a string, which is expected to be in ISO 8601 format.
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.
Expand Down
13 changes: 7 additions & 6 deletions docs/timezone.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,19 @@ tz2.getTransitions(now).next().done; // => false

## Static methods

### Temporal.TimeZone.**from**(_thing_: string | object) : Temporal.TimeZone
### Temporal.TimeZone.**from**(_thing_: any) : Temporal.TimeZone

**Parameters:**
- `thing` (string or object): A `Temporal.TimeZone` object or a string from which to create a `Temporal.TimeZone`.
- `thing`: A `Temporal.TimeZone` object or a value from which to create a `Temporal.TimeZone`.

**Returns:** a new `Temporal.TimeZone` object.
**Returns:** a new `Temporal.TimeZone` object (or the same object if `thing` was a `Temporal.TimeZone` object.)

This static method creates a new time zone from another value.
If the value is a string, it can be:
- a string that is accepted by `new Temporal.TimeZone()`;
If the value is another `Temporal.TimeZone` object, the same object is returned directly.

Any other value is converted to a string, which is expected to be either:
- a string that is accepted by `new Temporal.TimeZone()`; or
- a string in the ISO 8601 format including a time zone offset part.
Or, if the value is an object, it can be another `Temporal.TimeZone` object, which is returned directly.

Note that the ISO 8601 string can optionally be extended with an IANA time zone name in square brackets appended to it.

Expand Down
12 changes: 6 additions & 6 deletions docs/yearmonth.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ ym = new Temporal.YearMonth(2019, 6) // => 2019-06

## Static methods

### Temporal.YearMonth.**from**(_thing_: string | object, _options_?: object) : Temporal.YearMonth
### Temporal.YearMonth.**from**(_thing_: any, _options_?: object) : Temporal.YearMonth

**Parameters:**
- `thing` (string or object): The value representing the desired month.
- `thing`: The value representing the desired month.
- `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`.
Expand All @@ -47,13 +47,13 @@ ym = new Temporal.YearMonth(2019, 6) // => 2019-06
**Returns:** a new `Temporal.YearMonth` object (or the same object if `thing` was a `Temporal.YearMonth` object.)

This static method creates a new `Temporal.YearMonth` object from another value.
If the value is a string, it must be in ISO 8601 format.
Any parts of the string other than the year and the month are optional and will be ignored.
If the string isn't valid according to ISO 8601, then a `RangeError` will be thrown regardless of the value of `disambiguation`.

If the value is another `Temporal.YearMonth` object, the same object is returned.
If the value is any other object, it must have `year` and `month` properties, and a `Temporal.YearMonth` will be constructed from them.

Any non-object value is converted to a string, which is expected to be in ISO 8601 format.
Any parts of the string other than the year and the month are optional and will be ignored.
If the string isn't valid according to ISO 8601, then a `RangeError` will be thrown regardless of the value of `disambiguation`.

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.
Expand Down
9 changes: 7 additions & 2 deletions polyfill/lib/absolute.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,13 @@ export class Absolute {
return result;
}
static from(item) {
const absolute = ES.ToTemporalAbsolute(item);
const result = new this(bigIntIfAvailable(GetSlot(absolute, EPOCHNANOSECONDS)));
let absolute;
if (ES.IsTemporalAbsolute(item)) {
absolute = GetSlot(item, EPOCHNANOSECONDS);
} else {
absolute = ES.TemporalAbsoluteFromString(ES.ToString(item));
}
const result = new this(bigIntIfAvailable(absolute));
if (!ES.IsTemporalAbsolute(result)) throw new TypeError('invalid result');
return result;
}
Expand Down
11 changes: 9 additions & 2 deletions polyfill/lib/date.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,15 @@ export class Date {
}
static from(item, options = undefined) {
const disambiguation = ES.ToTemporalDisambiguation(options);
let result = ES.ToTemporalDate(item, disambiguation);
return new this(GetSlot(result, YEAR), GetSlot(result, MONTH), GetSlot(result, DAY));
let year, month, day;
if (typeof item === 'object' && item) {
// Intentionally alphabetical
({ year, month, day } = ES.ToRecord(item, ['day', 'month', 'year']));
} else {
({ year, month, day } = ES.ParseTemporalDateString(ES.ToString(item)));
}
({ year, month, day } = ES.RegulateDate(year, month, day, disambiguation));
return new this(year, month, day);
}
static compare(one, two) {
if (!ES.IsTemporalDate(one) || !ES.IsTemporalDate(two)) throw new TypeError('invalid Date object');
Expand Down
51 changes: 39 additions & 12 deletions polyfill/lib/datetime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -316,18 +316,45 @@ export class DateTime {

static from(item, options = undefined) {
const disambiguation = ES.ToTemporalDisambiguation(options);
let result = ES.ToTemporalDateTime(item, disambiguation);
return new this(
GetSlot(result, YEAR),
GetSlot(result, MONTH),
GetSlot(result, DAY),
GetSlot(result, HOUR),
GetSlot(result, MINUTE),
GetSlot(result, SECOND),
GetSlot(result, MILLISECOND),
GetSlot(result, MICROSECOND),
GetSlot(result, NANOSECOND)
);
let year, month, day, hour, minute, second, millisecond, microsecond, nanosecond;
if (typeof item === 'object' && item) {
({
year,
month,
day,
hour = 0,
minute = 0,
second = 0,
millisecond = 0,
microsecond = 0,
nanosecond = 0
} = ES.ToDateTimeRecord(item));
} else {
({
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond
} = ES.ParseTemporalDateTimeString(ES.ToString(item)));
}
({ year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = ES.RegulateDateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
disambiguation
));
return new this(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond);
}
static compare(one, two) {
if (!ES.IsTemporalDateTime(one) || !ES.IsTemporalDateTime(two)) throw new TypeError('invalid DateTime object');
Expand Down
68 changes: 55 additions & 13 deletions polyfill/lib/duration.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,17 @@ export class Duration {
with(durationLike, options) {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
const disambiguation = ES.ToTemporalDisambiguation(options);
const props = ES.ValidDurationLike(durationLike);
const props = ES.ToPartialRecord(durationLike, [
'years',
'months',
'days',
'hours',
'minutes',
'seconds',
'milliseconds',
'microseconds',
'nanoseconds'
]);
if (!props) {
throw new RangeError('invalid duration-like');
}
Expand Down Expand Up @@ -238,18 +248,50 @@ export class Duration {
}
static from(item, options = undefined) {
const disambiguation = ES.ToTemporalDisambiguation(options);
let result = ES.ToTemporalDuration(item, disambiguation);
return new this(
GetSlot(result, YEARS),
GetSlot(result, MONTHS),
GetSlot(result, DAYS),
GetSlot(result, HOURS),
GetSlot(result, MINUTES),
GetSlot(result, SECONDS),
GetSlot(result, MILLISECONDS),
GetSlot(result, MICROSECONDS),
GetSlot(result, NANOSECONDS)
);
let years, months, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds;
if (typeof item === 'object' && item) {
({
years = 0,
months = 0,
days = 0,
hours = 0,
minutes = 0,
seconds = 0,
milliseconds = 0,
microseconds = 0,
nanoseconds = 0
} = ES.ToRecord(
item,
[],
// Intentionally alphabetical
['days', 'hours', 'microseconds', 'milliseconds', 'minutes', 'months', 'nanoseconds', 'seconds', 'years']
));
} else {
({
years,
months,
days,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds
} = ES.ParseTemporalDurationString(ES.ToString(item)));
}
({ years, months, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.RegulateDuration(
years,
months,
days,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds,
disambiguation
));
return new this(years, months, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds);
}
}
Duration.prototype.toJSON = Duration.prototype.toString;
Expand Down
Loading

0 comments on commit e02a92c

Please sign in to comment.