assemblyscript-temporal
Advanced tools
Comparing version 1.8.0 to 1.9.0
@@ -5,3 +5,3 @@ module.exports = { | ||
*/ | ||
include: ["assembly/**/__tests__/**/*.spec.ts"], | ||
include: ["assembly/**/__tests__/**/dur*.spec.ts"], | ||
/** | ||
@@ -8,0 +8,0 @@ * A set of globs passed to the glob package that quality files to be added to each test. |
@@ -24,1 +24,5 @@ // @ts-ignore | ||
export const NANOS_PER_SECOND = 1_000_000_000; | ||
// @ts-ignore | ||
@lazy | ||
export const NANOS_PER_DAY = i64(MILLIS_PER_DAY) * 1_000_000; |
@@ -1,28 +0,33 @@ | ||
import { durationSign } from "./utils"; | ||
import { RegExp } from "assemblyscript-regex"; | ||
import { addDuration, coalesce, durationSign, sign } from "./utils"; | ||
import { MICROS_PER_SECOND, MILLIS_PER_SECOND, NANOS_PER_SECOND } from "./constants"; | ||
import { PlainDateTime } from "./plaindatetime"; | ||
const NULL = i32.MAX_VALUE; | ||
export class DurationLike { | ||
years: i32 = 0; | ||
months: i32 = 0; | ||
weeks: i32 = 0; | ||
days: i32 = 0; | ||
hours: i32 = 0; | ||
minutes: i32 = 0; | ||
seconds: i32 = 0; | ||
milliseconds: i32 = 0; | ||
microseconds: i32 = 0; | ||
nanoseconds: i32 = 0; | ||
years: i32 = NULL; | ||
months: i32 = NULL; | ||
weeks: i32 = NULL; | ||
days: i32 = NULL; | ||
hours: i32 = NULL; | ||
minutes: i32 = NULL; | ||
seconds: i32 = NULL; | ||
milliseconds: i32 = NULL; | ||
microseconds: i32 = NULL; | ||
nanoseconds: i32 = NULL; | ||
toDuration(): Duration { | ||
return new Duration( | ||
this.years, | ||
this.months, | ||
this.weeks, | ||
this.days, | ||
this.hours, | ||
this.minutes, | ||
this.seconds, | ||
this.milliseconds, | ||
this.microseconds, | ||
this.nanoseconds | ||
this.years != NULL ? this.years : 0, | ||
this.months != NULL ? this.months : 0, | ||
this.weeks != NULL ? this.weeks : 0, | ||
this.days != NULL ? this.days : 0, | ||
this.hours != NULL ? this.hours : 0, | ||
this.minutes != NULL ? this.minutes : 0, | ||
this.seconds != NULL ? this.seconds : 0, | ||
this.milliseconds != NULL ? this.milliseconds : 0, | ||
this.microseconds != NULL ? this.microseconds : 0, | ||
this.nanoseconds != NULL ? this.nanoseconds : 0, | ||
); | ||
@@ -33,2 +38,44 @@ } | ||
export class Duration { | ||
static from<T = DurationLike>(date: T): Duration { | ||
if (isString<T>()) { | ||
// @ts-ignore: cast | ||
return this.fromString(<string>date); | ||
} else if (date instanceof DurationLike) { | ||
return this.fromDurationLike(date); | ||
} | ||
throw new TypeError("invalid duration type"); | ||
} | ||
private static fromString(duration: string): Duration { | ||
const regex = new RegExp( | ||
"([+−-])?P(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)W)?(?:(\\d+)D)?(?:T?(?:(\\d+)?H)?(?:(\\d+)?M)?(?:(\\d+)(?:[.,](\\d{1,9}))?S)?)?$", | ||
"i" | ||
); | ||
const match = regex.exec(duration); | ||
if (match == null) { | ||
throw new RangeError("invalid duration: " + duration); | ||
} | ||
if (match.matches.slice(2).join("") == "") { | ||
throw new RangeError("invalid duration"); | ||
} | ||
const sign = match.matches[1] == '-' || match.matches[1] == '\u2212' ? -1 : 1; | ||
const years = match.matches[2] != "" ? I32.parseInt(match.matches[2]) * sign : 0; | ||
const months = match.matches[3] != "" ? I32.parseInt(match.matches[3]) * sign : 0; | ||
const weeks = match.matches[4] != "" ? I32.parseInt(match.matches[4]) * sign : 0; | ||
const days = match.matches[5] != "" ? I32.parseInt(match.matches[5]) * sign : 0; | ||
const hours = match.matches[6] != "" ? I32.parseInt(match.matches[6]) * sign : 0; | ||
const minutes = match.matches[7] != "" ? I32.parseInt(match.matches[7]) * sign : 0; | ||
const seconds = match.matches[8] != "" ? I32.parseInt(match.matches[8]) * sign : 0; | ||
const fraction = match.matches[9] + "000000000"; | ||
const millisecond = I32.parseInt(fraction.substring(0, 3)) * sign; | ||
const microsecond = I32.parseInt(fraction.substring(3, 6)) * sign; | ||
const nanosecond = I32.parseInt(fraction.substring(6, 9)) * sign; | ||
return new Duration(years, months, weeks, days, hours, minutes, seconds, millisecond, microsecond, nanosecond); | ||
} | ||
private static fromDurationLike(d: DurationLike): Duration { | ||
return d.toDuration(); | ||
} | ||
constructor( | ||
@@ -45,4 +92,35 @@ public years: i32 = 0, | ||
public nanoseconds: i32 = 0 | ||
) {} | ||
) { | ||
// durationSign returns the sign of the first non-zero component | ||
const s = this.sign; | ||
if ((years && sign(years) != s) || | ||
(months && sign(months) != s) || | ||
(weeks && sign(weeks) != s) || | ||
(days && sign(days) != s) || | ||
(hours && sign(hours) != s) || | ||
(minutes && sign(minutes) != s) || | ||
(seconds && sign(seconds) != s) || | ||
(milliseconds && sign(milliseconds) != s) || | ||
(microseconds && sign(microseconds) != s) || | ||
(nanoseconds && sign(nanoseconds) != s) | ||
) { | ||
throw new RangeError("mixed-sign values not allowed as duration fields"); | ||
} | ||
} | ||
with(durationLike: DurationLike): Duration { | ||
return new Duration( | ||
coalesce(durationLike.years, this.years, NULL), | ||
coalesce(durationLike.months, this.months, NULL), | ||
coalesce(durationLike.weeks, this.weeks, NULL), | ||
coalesce(durationLike.days, this.days, NULL), | ||
coalesce(durationLike.hours, this.hours, NULL), | ||
coalesce(durationLike.minutes, this.minutes, NULL), | ||
coalesce(durationLike.seconds, this.seconds, NULL), | ||
coalesce(durationLike.milliseconds, this.milliseconds, NULL), | ||
coalesce(durationLike.microseconds, this.microseconds, NULL), | ||
coalesce(durationLike.nanoseconds, this.nanoseconds, NULL) | ||
); | ||
} | ||
get sign(): i32 { | ||
@@ -74,8 +152,9 @@ return durationSign( | ||
toString(abs(this.minutes), "M") + | ||
toString( | ||
// sort in ascending order for better sum precision | ||
f64(this.nanoseconds) / NANOS_PER_SECOND + | ||
f64(this.microseconds) / MICROS_PER_SECOND + | ||
f64(this.milliseconds) / MILLIS_PER_SECOND + | ||
f64(this.seconds), | ||
toString(abs( | ||
// sort in ascending order for better sum precision | ||
f64(this.nanoseconds) / NANOS_PER_SECOND + | ||
f64(this.microseconds) / MICROS_PER_SECOND + | ||
f64(this.milliseconds) / MILLIS_PER_SECOND + | ||
f64(this.seconds) | ||
), | ||
"S" | ||
@@ -89,4 +168,67 @@ ); | ||
} | ||
add<T = DurationLike>(durationToAdd: T, relativeTo: PlainDateTime | null = null): Duration { | ||
const duration = | ||
durationToAdd instanceof DurationLike | ||
? durationToAdd.toDuration() | ||
// @ts-ignore TS2352 | ||
: durationToAdd as Duration; | ||
return addDuration(this.years, | ||
this.months, | ||
this.weeks, | ||
this.days, | ||
this.hours, | ||
this.minutes, | ||
this.seconds, | ||
this.milliseconds, | ||
this.microseconds, | ||
this.nanoseconds, | ||
duration.years, | ||
duration.months, | ||
duration.weeks, | ||
duration.days, | ||
duration.hours, | ||
duration.minutes, | ||
duration.seconds, | ||
duration.milliseconds, | ||
duration.microseconds, | ||
duration.nanoseconds, | ||
relativeTo | ||
); | ||
} | ||
subtract<T = DurationLike>(durationToAdd: T, relativeTo: PlainDateTime | null = null): Duration { | ||
const duration = | ||
durationToAdd instanceof DurationLike | ||
? durationToAdd.toDuration() | ||
// @ts-ignore TS2352 | ||
: durationToAdd as Duration; | ||
return addDuration(this.years, | ||
this.months, | ||
this.weeks, | ||
this.days, | ||
this.hours, | ||
this.minutes, | ||
this.seconds, | ||
this.milliseconds, | ||
this.microseconds, | ||
this.nanoseconds, | ||
-duration.years, | ||
-duration.months, | ||
-duration.weeks, | ||
-duration.days, | ||
-duration.hours, | ||
-duration.minutes, | ||
-duration.seconds, | ||
-duration.milliseconds, | ||
-duration.microseconds, | ||
-duration.nanoseconds, | ||
relativeTo | ||
); | ||
} | ||
} | ||
function toString<T extends number>(value: T, suffix: string): string { | ||
@@ -102,2 +244,2 @@ return value | ||
return F64.isSafeInteger(value) ? i64(value).toString() : value.toString(); | ||
} | ||
} |
@@ -6,2 +6,9 @@ export const enum Overflow { | ||
export const enum Disambiguation { | ||
Compatible, | ||
Earlier, | ||
Later, | ||
Reject, | ||
} | ||
export const enum TimeComponent { | ||
@@ -8,0 +15,0 @@ Years, |
@@ -18,3 +18,6 @@ import { RegExp } from "assemblyscript-regex"; | ||
parseISOString, | ||
leapYear, | ||
epochFromParts, | ||
} from "./utils"; | ||
import { PlainDate } from "./plaindate"; | ||
@@ -146,2 +149,13 @@ export class DateTimeLike { | ||
@inline | ||
get inLeapYear(): bool { | ||
return leapYear(this.year); | ||
} | ||
@inline | ||
get epochNanoseconds(): i64 { | ||
return epochFromParts(this.year, this.month, this.day, this.hour, this.minute, | ||
this.second, this.millisecond, this.microsecond, this.nanosecond) | ||
} | ||
with(dateTimeLike: DateTimeLike): PlainDateTime { | ||
@@ -199,2 +213,10 @@ return new PlainDateTime( | ||
toPlainDate(): PlainDate { | ||
return new PlainDate( | ||
this.year, | ||
this.month, | ||
this.day | ||
); | ||
} | ||
static compare(a: PlainDateTime, b: PlainDateTime): i32 { | ||
@@ -201,0 +223,0 @@ if (a === b) return 0; |
@@ -6,14 +6,16 @@ import { Instant } from "./instant"; | ||
balanceDateTime, | ||
formatTimeZoneOffsetString, | ||
formatTimeZoneOffsetString | ||
} from "./utils"; | ||
import { offsetForTimezone } from "./tz/index"; | ||
import { offsetForTimezoneNanos, offsetForTimezone } from "./tz/index"; | ||
import { Disambiguation } from "./enums"; | ||
import { DurationLike } from "./duration"; | ||
import { MILLIS_PER_DAY, NANOS_PER_DAY } from "./constants"; | ||
export class TimeZone { | ||
constructor(public timezone: string) {} | ||
constructor(public id: string) {} | ||
getOffsetNanosecondsFor(instant: Instant): i64 { | ||
return this.timezone == "UTC" | ||
return this.id == "UTC" | ||
? 0 | ||
: i64(offsetForTimezone(this.timezone, instant.epochMilliseconds)) * | ||
1_000_000; | ||
: offsetForTimezoneNanos(this.id, instant.epochNanoseconds); | ||
} | ||
@@ -54,2 +56,85 @@ | ||
} | ||
getPossibleInstantsFor(dateTime: PlainDateTime): Instant[] { | ||
// see: ES.GetIANATimeZoneEpochValue | ||
const epochNanos = dateTime.epochNanoseconds; | ||
const earliest = offsetForTimezoneNanos(this.id, epochNanos - NANOS_PER_DAY); | ||
const latest = offsetForTimezoneNanos(this.id, epochNanos + NANOS_PER_DAY); | ||
const earliestDateTime = this.getPlainDateTimeFor( | ||
new Instant(epochNanos - earliest) | ||
); | ||
const latestDateTime = this.getPlainDateTimeFor( | ||
new Instant(epochNanos - latest) | ||
); | ||
if (earliest == latest) { | ||
if (earliestDateTime.equals(dateTime)) { | ||
return [new Instant(epochNanos - earliest)]; | ||
} else { | ||
return []; | ||
} | ||
} | ||
let instants = new Array<Instant>(); | ||
if (earliestDateTime.equals(dateTime)) { | ||
instants.push(new Instant(epochNanos - earliest)); | ||
} | ||
if (latestDateTime.equals(dateTime)) { | ||
instants.push(new Instant(epochNanos - latest)); | ||
} | ||
return instants; | ||
} | ||
getInstantFor( | ||
dateTime: PlainDateTime, | ||
disambiguation: Disambiguation = Disambiguation.Compatible | ||
): Instant { | ||
const possibleInstants = this.getPossibleInstantsFor(dateTime); | ||
if (possibleInstants.length == 1) { | ||
return possibleInstants[0]; | ||
} | ||
if (possibleInstants.length == 2) { | ||
switch (disambiguation) { | ||
case Disambiguation.Compatible: | ||
// fall through because 'compatible' means 'earlier' for "fall back" transitions | ||
case Disambiguation.Earlier: | ||
return possibleInstants[0]; | ||
case Disambiguation.Later: | ||
return possibleInstants[possibleInstants.length - 1]; | ||
case Disambiguation.Reject: | ||
throw new RangeError("multiple instants found"); | ||
} | ||
} | ||
const instant = new Instant(dateTime.epochNanoseconds); | ||
const offsetBefore = offsetForTimezone( | ||
this.id, | ||
instant.epochMilliseconds - MILLIS_PER_DAY | ||
); | ||
const offsetAfter = offsetForTimezone( | ||
this.id, | ||
instant.epochMilliseconds + MILLIS_PER_DAY | ||
); | ||
const milliseconds = offsetAfter - offsetBefore; | ||
switch (disambiguation) { | ||
case Disambiguation.Earlier: { | ||
const earlier = dateTime.subtract({ milliseconds: milliseconds }); | ||
return this.getPossibleInstantsFor(earlier)[0]; | ||
} | ||
case Disambiguation.Compatible: | ||
// fall through because 'compatible' means 'later' for "spring forward" transitions | ||
case Disambiguation.Later: { | ||
const later = dateTime.add({ milliseconds: milliseconds }); | ||
const possible = this.getPossibleInstantsFor(later); | ||
return possible[possible.length - 1]; | ||
} | ||
case Disambiguation.Reject: { | ||
throw new RangeError("no such instant found"); | ||
} | ||
} | ||
throw new RangeError("no such instant found"); | ||
} | ||
} |
@@ -37,1 +37,5 @@ import { zones, rules } from "./iana"; | ||
} | ||
export function offsetForTimezoneNanos(tz: string, epochNanos: i64): i64 { | ||
return i64(offsetForTimezone(tz, epochNanos / 1_000_000)) * 1_000_000; | ||
} |
@@ -15,2 +15,6 @@ // for the proposal-temporal implementation, most of the business logic | ||
import { JsDate } from "./date"; | ||
import { TimeZone } from "./timezone"; | ||
import { Instant } from "./instant"; | ||
import { PlainDate } from "./plaindate"; | ||
import { PlainDateTime } from "./plaindatetime"; | ||
@@ -68,3 +72,3 @@ // @ts-ignore | ||
days: i32; | ||
nanoseconds: i32; | ||
nanoseconds: i64; | ||
dayLengthNs: i64; | ||
@@ -448,3 +452,3 @@ } | ||
days: i32(ns / oneDayNs), | ||
nanoseconds: i32(ns % oneDayNs), | ||
nanoseconds: i64(ns % oneDayNs), | ||
dayLengthNs: oneDayNs * sign(ns) | ||
@@ -497,3 +501,3 @@ }; | ||
nanosecondsI64 = abs(nanosecondsI64); | ||
switch (largestUnit) { | ||
@@ -807,25 +811,5 @@ case TimeComponent.Years: | ||
nanosecond: i32 | ||
): u64 { | ||
// Note: Date.UTC() interprets one and two-digit years as being in the | ||
// 20th century, so don't use it | ||
// TODO: need implementation | ||
// const legacyDate = new Date(); | ||
// legacyDate.setUTCHours(hour, minute, second, millisecond); | ||
// legacyDate.setUTCFullYear(year, month - 1, day); | ||
// const ms = legacyDate.getTime(); | ||
// if (NumberIsNaN(ms)) return null; | ||
// let ns = bigInt(ms).multiply(1e6); | ||
// ns = ns.plus(bigInt(microsecond).multiply(1000)); | ||
// ns = ns.plus(bigInt(nanosecond)); | ||
// if (ns.lesser(NS_MIN) || ns.greater(NS_MAX)) { | ||
// __null = true; | ||
// return 0; | ||
// } | ||
// __null = false; | ||
// return ns; | ||
__null = false; | ||
return 0; | ||
): i64 { | ||
const millis = Date.UTC(year, month - 1, day, hour, minute, second, millisecond); | ||
return millis * 1_000_000 + microsecond * 1_000 + nanosecond; | ||
} | ||
@@ -1090,2 +1074,70 @@ | ||
} | ||
} | ||
function addInstant(epochNanoseconds: i64, h: i32, min: i32, s: i32, ms: i32, µs: i32, ns: i32): i64 { | ||
return epochNanoseconds + ns + µs * 1_000 + ms * 1_000_000 + s * 1_000_000_000 * min * 60_000_000_000 + h * 3_600_000_000_000; | ||
} | ||
function largestDurationUnit(y: i32, mon: i32, w: i32, d: i32, h: i32, min: i32, s: i32, ms: i32, µs: i32, ns: i32): TimeComponent { | ||
if (y != 0) return TimeComponent.Years; | ||
if (mon != 0) return TimeComponent.Months; | ||
if (w != 0) return TimeComponent.Weeks; | ||
if (d != 0) return TimeComponent.Days; | ||
if (h != 0) return TimeComponent.Hours; | ||
if (min != 0) return TimeComponent.Minutes; | ||
if (s != 0) return TimeComponent.Seconds; | ||
if (ms != 0) return TimeComponent.Milliseconds; | ||
if (µs != 0) return TimeComponent.Microseconds; | ||
return TimeComponent.Nanoseconds; | ||
} | ||
export function addDuration(y1: i32, mon1: i32, w1: i32, d1: i32, h1: i32, min1: i32, s1: i32, ms1: i32, µs1: i32, ns1: i32, | ||
y2: i32, mon2: i32, w2: i32, d2: i32, h2: i32, min2: i32, s2: i32, ms2: i32, µs2: i32, ns2: i32, | ||
relativeTo: PlainDateTime | null | ||
): Duration { | ||
const largestUnit1 = largestDurationUnit(y1, mon1, w1, d1, h1, min1, s1, ms1, µs1, ns1); | ||
const largestUnit2 = largestDurationUnit(y2, mon2, w2, d2, h2, min2, s2, ms2, µs2, ns2); | ||
const largestUnit = min(largestUnit1, largestUnit2) as TimeComponent; | ||
if (!relativeTo) { | ||
if (largestUnit == TimeComponent.Years || largestUnit == TimeComponent.Months || largestUnit == TimeComponent.Weeks) { | ||
throw new RangeError("relativeTo is required for years, months, or weeks arithmetic"); | ||
} | ||
const balanced = balanceDuration( | ||
d1 + d2, | ||
h1 + h2, | ||
min1 + min2, | ||
s1 + s2, | ||
ms1 + ms2, | ||
µs1 + µs2, | ||
ns1 + ns2, | ||
largestUnit | ||
); | ||
return balanced; | ||
} else { | ||
const datePart = relativeTo.toPlainDate(); | ||
const dateDuration1 = new Duration(y1, mon1, w1, d1, 0, 0, 0, 0, 0, 0); | ||
const dateDuration2 = new Duration(y2, mon2, w2, d2, 0, 0, 0, 0, 0, 0); | ||
const intermediate = datePart.add(dateDuration1); | ||
const end = intermediate.add(dateDuration2); | ||
const dateLargestUnit = min(largestUnit, TimeComponent.Days) as TimeComponent; | ||
const dateDiff = datePart.until(end, dateLargestUnit); | ||
const dur = balanceDuration( | ||
dateDiff.days, | ||
h1 + h2, | ||
min1 + min2, | ||
s1 + s2, | ||
ms1 + ms2, | ||
µs1 + µs2, | ||
ns1 + ns2, | ||
largestUnit | ||
); | ||
return new Duration(dateDiff.years, dateDiff.months, dateDiff.weeks, dur.days, dur.hours, dur.minutes, | ||
dur.seconds, dur.milliseconds, dur.microseconds, dur.nanoseconds); | ||
} | ||
} |
import { RegExp } from "assemblyscript-regex"; | ||
import { DurationLike } from "./duration"; | ||
import { Overflow } from "./enums"; | ||
import { Instant } from "./instant"; | ||
@@ -7,3 +9,3 @@ import { DateTimeLike, PlainDateTime } from "./plaindatetime"; | ||
import { JsDate } from "./date"; | ||
import { parseISOString } from "./utils"; | ||
import { dayOfWeek, dayOfYear, daysInMonth, daysInYear, leapYear, parseISOString, weekOfYear } from "./utils"; | ||
@@ -100,2 +102,63 @@ export class ZonedDateTime { | ||
get epochSeconds(): i32 { | ||
return i32(this.epochNanos / 1_000_000_000); | ||
} | ||
get epochMilliseconds(): i32 { | ||
return i32(this.epochNanos / 1_000_000); | ||
} | ||
get epochMicroseconds(): i64 { | ||
return this.epochNanos / 1_000; | ||
} | ||
get epochNanoseconds(): i64 { | ||
return this.epochNanos; | ||
} | ||
@inline | ||
get dayOfWeek(): i32 { | ||
return dayOfWeek(this.year, this.month, this.day); | ||
} | ||
@inline | ||
get dayOfYear(): i32 { | ||
return dayOfYear(this.year, this.month, this.day); | ||
} | ||
@inline | ||
get weekOfYear(): i32 { | ||
return weekOfYear(this.year, this.month, this.day); | ||
} | ||
@inline | ||
get daysInWeek(): i32 { | ||
return 7; | ||
} | ||
@inline | ||
get daysInMonth(): i32 { | ||
return daysInMonth(this.year, this.month); | ||
} | ||
@inline | ||
get daysInYear(): i32 { | ||
return daysInYear(this.year); | ||
} | ||
@inline | ||
get monthsInYear(): i32 { | ||
return 12; | ||
} | ||
@inline | ||
get inLeapYear(): bool { | ||
return leapYear(this.year); | ||
} | ||
@inline | ||
get offsetNanoseconds(): i64 { | ||
return this.tz.getOffsetNanosecondsFor(this.toInstant()); | ||
} | ||
toString(): string { | ||
@@ -106,6 +169,18 @@ return ( | ||
"[" + | ||
this.tz.timezone + | ||
this.tz.id + | ||
"]" | ||
); | ||
} | ||
// add<T = DurationLike>(durationToAdd: T, overflow: Overflow = Overflow.Constrain): ZonedDateTime { | ||
// const duration = | ||
// durationToAdd instanceof DurationLike | ||
// ? durationToAdd.toDuration() | ||
// // @ts-ignore TS2352 | ||
// : durationToAdd as Duration; | ||
// } | ||
} |
@@ -0,1 +1,13 @@ | ||
## Development and roadmap | ||
This is a very large library, therefore a prioritised roadmap is important. The following is the rough priority order: | ||
1. Non-timezone aware classes, i.e. `PlainDate`, `PlainDateTime`, etc with a hard-coded Gregorian calendar. | ||
2. Ancillary classes, i.e. `Instant`, `Duration` and `now` | ||
3. Time-zone aware classes, `TimeZone`, `ZonedDateTime`, etc | ||
4. Non gregorian calendar systems | ||
So far much of (1) has been implemented. Also a 'spike' implementation of (3) has been added to determine a suitable approach for implementing timezone offsets. | ||
### Implementation approach | ||
@@ -6,5 +18,4 @@ | ||
1. Use the temporal polyfill test cases as a means to ensure implementation correctness. Currently these test cases are cut / paste with a few tweaks. Ideally this would be automated to ensure parity going forwards | ||
2. Start simple ... start with `PlainDate` | ||
3. Use the polyfill implementation as a starting point. However, it is riddled with JS-specific code that doesn't make sense to port. However, most of the algorithmic code is [within a single file](https://github.com/tc39/proposal-temporal/blob/main/polyfill/lib/ecmascript.mjs), which can be ported relatively easily. | ||
4. Don't bother refactoring heavily, being able to map between the polyfill implementation and this codebase will help ensure correctness | ||
2. Use the polyfill implementation as a starting point. However, it is riddled with JS-specific code that doesn't make sense to port. However, most of the algorithmic code is [within a single file](https://github.com/tc39/proposal-temporal/blob/main/polyfill/lib/ecmascript.mjs), which can be ported relatively easily. | ||
3. Don't bother refactoring heavily, being able to map between the polyfill implementation and this codebase will help ensure correctness | ||
@@ -239,3 +250,4 @@ ### Implementation progress | ||
- [ ] toZonedDateTime | ||
- [ ] toPlainDateTime | ||
- [x] toPlainDate | ||
- [x] toPlainTime | ||
- [ ] toPlainYearMonth | ||
@@ -278,5 +290,5 @@ - [ ] toPlainMonthDay | ||
- [ ] with | ||
- [ ] add | ||
- [ ] subtract | ||
- [x] with | ||
- [x] add | ||
- [x] subtract | ||
- [ ] negated | ||
@@ -294,1 +306,121 @@ - [ ] abs | ||
- [ ] precision - need to determine what type to use for the properties | ||
#### ZonedDateTime | ||
Constructor | ||
- [x] new Temporal.ZonedDateTime | ||
Static methods | ||
- [ ] from | ||
- [ ] compare | ||
Properties | ||
- [x] year | ||
- [x] month | ||
- [x] day | ||
- [x] hour | ||
- [x] minute | ||
- [x] second | ||
- [x] millisecond | ||
- [x] microsecond | ||
- [x] nanosecond | ||
- [x] epochSeconds | ||
- [x] epochMilliseconds | ||
- [x] epochMicroseconds | ||
- [x] epochNanoseconds | ||
- [ ] calendar | ||
- [x] timeZone | ||
- [ ] era | ||
- [ ] eraYear | ||
- [x] dayOfWeek | ||
- [x] dayOfYear | ||
- [x] weekOfYear | ||
- [x] daysInWeek | ||
- [x] daysInMonth | ||
- [x] daysInYear | ||
- [x] monthsInYear | ||
- [x] inLeapYear | ||
- [x] hoursInDay | ||
- [ ] startOfDay | ||
- [x] offsetNanoseconds | ||
- [x] offset | ||
Methods | ||
- [ ] with | ||
- [ ] withPlainTime | ||
- [ ] withPlainDate | ||
- [ ] withTimeZone | ||
- [ ] withCalendar | ||
- [ ] add | ||
- [ ] subtract | ||
- [ ] until | ||
- [ ] since | ||
- [ ] round | ||
- [ ] equals | ||
- [ ] toString | ||
- [ ] toLocaleString | ||
- [ ] toJSON | ||
- [ ] valueOf | ||
- [ ] toInstant | ||
- [ ] toPlainDate | ||
- [ ] toPlainTime | ||
- [ ] toPlainDateTime | ||
- [ ] toPlainYearMonth | ||
- [ ] toPlainMonthDay | ||
- [ ] getISOFields | ||
#### Instant | ||
Constructor | ||
- [x] new Temporal.Instant | ||
Static methods | ||
- [ ] from | ||
- [ ] fromEpochSeconds | ||
- [ ] fromEpochMilliseconds | ||
- [ ] fromEpochMicroseconds | ||
- [ ] fromEpochNanoseconds | ||
- [ ] compare | ||
Properties | ||
- [x] epochSeconds | ||
- [x] epochMilliseconds | ||
- [x] epochMicroseconds | ||
- [x] epochNanoseconds | ||
Methods | ||
- [ ] toZonedDateTimeISO | ||
- [ ] toZonedDateTime | ||
- [ ] add | ||
- [ ] subtract | ||
- [ ] until | ||
- [ ] since | ||
- [ ] round | ||
- [ ] equals | ||
- [ ] toString | ||
- [ ] toLocaleString | ||
- [ ] toJSON | ||
- [ ] valueOf | ||
#### TimeZone | ||
Constructor | ||
- [x] new Temporal.TimeZone | ||
Static methods | ||
- [ ] from | ||
Properties | ||
- [x] id | ||
Methods | ||
- [x] getOffsetNanosecondsFor | ||
- [x] getOffsetStringFor | ||
- [x] getPlainDateTimeFor | ||
- [ ] getInstantFor | ||
- [x] getPossibleInstantsFor | ||
- [ ] getNextTransition | ||
- [ ] getPreviousTransition | ||
- [ ] toString | ||
- [ ] toJSON |
{ | ||
"name": "assemblyscript-temporal", | ||
"version": "1.8.0", | ||
"version": "1.9.0", | ||
"description": "An implementation of temporal within AssemblyScript, with an initial focus on non-timezone-aware classes and functionality.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -108,1 +108,3 @@ ## assemblyscript-temporal | ||
This project is open source, MIT licensed and your contributions are very much welcomed. | ||
There is a [brief document that outlines implementation progress and priorities](./development.md). |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
2562439
80
26303
110