@jauntywunderkind/tc39-temporal
Version:
TC39 Proposal: Temporal
162 lines (157 loc) • 6.66 kB
JavaScript
import { ES } from './ecmascript.mjs';
import { MakeIntrinsicClass } from './intrinsicclass.mjs';
import { YEAR, MONTH, DAY, CreateSlots, GetSlot, SetSlot } from './slots.mjs';
import { date as STRING } from './regex.mjs';
export class Date {
constructor(year, month, day, disambiguation = 'constrain') {
year = ES.ToInteger(year);
month = ES.ToInteger(month);
day = ES.ToInteger(day);
disambiguation = ES.ToString(disambiguation);
switch (disambiguation) {
case 'reject':
ES.RejectDate(year, month, day);
break;
case 'constrain':
({ year, month, day } = ES.ConstrainDate(year, month, day));
break;
case 'balance':
({ year, month, day } = ES.BalanceDate(year, month, day));
break;
default:
throw new TypeError('disambiguation should be either reject, constrain or balance');
}
CreateSlots(this);
SetSlot(this, YEAR, year);
SetSlot(this, MONTH, month);
SetSlot(this, DAY, day);
}
get year() {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
return GetSlot(this, YEAR);
}
get month() {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
return GetSlot(this, MONTH);
}
get day() {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
return GetSlot(this, DAY);
}
get dayOfWeek() {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
return ES.DayOfWeek(GetSlot(this, YEAR), GetSlot(this, MONTH), GetSlot(this, DAY));
}
get dayOfYear() {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
return ES.DayOfYear(GetSlot(this, YEAR), GetSlot(this, MONTH), GetSlot(this, DAY));
}
get weekOfYear() {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
return ES.WeekOfYear(GetSlot(this, YEAR), GetSlot(this, MONTH), GetSlot(this, DAY));
}
get daysInYear() {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
return ES.LeapYear(GetSlot(this, YEAR)) ? 366 : 365;
}
get daysInMonth() {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
return ES.DaysInMonth(GetSlot(this, YEAR), GetSlot(this, MONTH));
}
get leapYear() {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
return ES.LeapYear(GetSlot(this, YEAR));
}
with(dateLike = {}, disambiguation = 'constrain') {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
const props = ES.ValidPropertyBag(dateLike, ['year', 'month', 'day']);
if (!props) {
throw new RangeError('invalid date-like');
}
const { year = GetSlot(this, YEAR), month = GetSlot(this, MONTH), day = GetSlot(this, DAY) } = props;
const Construct = ES.SpeciesConstructor(this, Date);
return new Construct(year, month, day, disambiguation);
}
plus(durationLike = {}, disambiguation = 'constrain') {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
const duration = ES.ToDuration(durationLike);
if (!ES.ValidDuration(duration, ['hours', 'minutes', 'seconds', 'milliseconds', 'microseconds', 'nanoseconds'])) {
throw new RangeError('invalid duration');
}
let { year, month, day } = this;
const { years, months, days } = duration;
({ year, month, day } = ES.AddDate(year, month, day, years, months, days, disambiguation));
const Construct = ES.SpeciesConstructor(this, Date);
return new Construct(year, month, day);
}
minus(durationLike = {}, disambiguation = 'constrain') {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
const duration = ES.ToDuration(durationLike);
if (!ES.ValidDuration(duration, ['hours', 'minutes', 'seconds', 'milliseconds', 'microseconds', 'nanoseconds'])) {
throw new RangeError('invalid duration');
}
let { year, month, day } = this;
const { years, months, days } = duration;
({ year, month, day } = ES.SubtractDate(year, month, day, years, months, days, disambiguation));
const Construct = ES.SpeciesConstructor(this, Date);
return new Construct(year, month, day);
}
difference(other) {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
const [smaller, larger] = [this, other].sort(Date.compare);
const { years, months, days } = ES.DifferenceDate(smaller, larger);
const Duration = ES.GetIntrinsic('%Temporal.Duration%');
return new Duration(years, months, days, 0, 0, 0, 0, 0, 0);
}
toString() {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
let year = ES.ISOYearString(GetSlot(this, YEAR));
let month = ES.ISODateTimePartString(GetSlot(this, MONTH));
let day = ES.ISODateTimePartString(GetSlot(this, DAY));
let resultString = `${year}-${month}-${day}`;
return resultString;
}
toLocaleString(...args) {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
return new Intl.DateTimeFormat(...args).format(this);
}
withTime(timeLike, disambiguation = 'constrain') {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
const year = GetSlot(this, YEAR);
const month = GetSlot(this, MONTH);
const day = GetSlot(this, DAY);
timeLike = ES.ToTime(timeLike);
const { hour, minute, second, millisecond, microsecond, nanosecond } = timeLike;
const DateTime = ES.GetIntrinsic('%Temporal.DateTime%');
return new DateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, disambiguation);
}
getYearMonth() {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
const YearMonth = ES.GetIntrinsic('%Temporal.YearMonth%');
return new YearMonth(GetSlot(this, YEAR), GetSlot(this, MONTH));
}
getMonthDay() {
if (!ES.IsDate(this)) throw new TypeError('invalid receiver');
const MonthDay = ES.GetIntrinsic('%Temporal.MonthDay%');
return new MonthDay(GetSlot(this, MONTH), GetSlot(this, DAY));
}
static from(arg) {
let result = ES.ToDate(arg);
return this === Date ? result : new this(
GetSlot(result, YEAR),
GetSlot(result, MONTH),
GetSlot(result, DAY),
'reject'
);
}
static compare(one, two) {
if (!ES.IsDate(one) || !ES.IsDate(two)) throw new TypeError('invalid Date object');
if (one.year !== two.year) return ES.ComparisonResult(one.year - two.year);
if (one.month !== two.month) return ES.ComparisonResult(one.month - two.month);
if (one.day !== two.day) return ES.ComparisonResult(one.day - two.day);
return ES.ComparisonResult(0);
}
}
export default Date
Date.prototype.toJSON = Date.prototype.toString;
MakeIntrinsicClass(Date, 'Temporal.Date');