Skip to content

Commit 8cb7134

Browse files
authored
Use JSBI instead of big-integer (#77)
1 parent e9c439b commit 8cb7134

12 files changed

+383
-320
lines changed

index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export namespace Temporal {
22
export type ComparisonResult = -1 | 0 | 1;
3-
type RoundingMode = 'halfExpand' | 'ceil' | 'trunc' | 'floor';
3+
export type RoundingMode = 'halfExpand' | 'ceil' | 'trunc' | 'floor';
44

55
/**
66
* Options for assigning fields using `with()` or entire objects with

lib/duration.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
} from './slots';
1919
import { Temporal } from '..';
2020
import type { DurationParams as Params, DurationReturn as Return } from './internaltypes';
21+
import JSBI from 'jsbi';
2122

2223
export class Duration implements Temporal.Duration {
2324
constructor(
@@ -517,7 +518,7 @@ export class Duration implements Temporal.Duration {
517518
}
518519
const totalNs1 = ES.TotalDurationNanoseconds(d1, h1, min1, s1, ms1, µs1, ns1, shift1);
519520
const totalNs2 = ES.TotalDurationNanoseconds(d2, h2, min2, s2, ms2, µs2, ns2, shift2);
520-
return ES.ComparisonResult(totalNs1.minus(totalNs2).toJSNumber());
521+
return ES.ComparisonResult(JSBI.toNumber(JSBI.subtract(totalNs1, totalNs2)));
521522
}
522523
[Symbol.toStringTag]!: 'Temporal.Duration';
523524
}

lib/ecmascript.ts

Lines changed: 318 additions & 252 deletions
Large diffs are not rendered by default.

lib/instant.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import { Temporal } from '..';
66
import { DateTimeFormat } from './intl';
77
import type { InstantParams as Params, InstantReturn as Return } from './internaltypes';
88

9-
import bigInt from 'big-integer';
9+
import JSBI from 'jsbi';
10+
import { BILLION, MILLION, THOUSAND } from './ecmascript';
1011

1112
const DISALLOWED_UNITS = ['year', 'month', 'week', 'day'] as const;
1213
const MAX_DIFFERENCE_INCREMENTS = {
@@ -19,7 +20,7 @@ const MAX_DIFFERENCE_INCREMENTS = {
1920
};
2021

2122
export class Instant implements Temporal.Instant {
22-
constructor(epochNanoseconds: bigint | bigInt.BigInteger) {
23+
constructor(epochNanoseconds: bigint | JSBI) {
2324
// Note: if the argument is not passed, ToBigInt(undefined) will throw. This check exists only
2425
// to improve the error message.
2526
if (arguments.length < 1) {
@@ -45,21 +46,21 @@ export class Instant implements Temporal.Instant {
4546
get epochSeconds(): Return['epochSeconds'] {
4647
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
4748
const value = GetSlot(this, EPOCHNANOSECONDS);
48-
return +value.divide(1e9);
49+
return JSBI.toNumber(JSBI.divide(value, BILLION));
4950
}
5051
get epochMilliseconds(): Return['epochMilliseconds'] {
5152
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
52-
const value = bigInt(GetSlot(this, EPOCHNANOSECONDS));
53-
return +value.divide(1e6);
53+
const value = JSBI.BigInt(GetSlot(this, EPOCHNANOSECONDS));
54+
return JSBI.toNumber(JSBI.divide(value, MILLION));
5455
}
5556
get epochMicroseconds(): Return['epochMicroseconds'] {
5657
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
57-
const value = GetSlot(this, EPOCHNANOSECONDS);
58-
return bigIntIfAvailable(value.divide(1e3));
58+
const value = JSBI.BigInt(GetSlot(this, EPOCHNANOSECONDS));
59+
return ES.ToBigIntExternal(JSBI.divide(value, THOUSAND));
5960
}
6061
get epochNanoseconds(): Return['epochNanoseconds'] {
6162
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
62-
return bigIntIfAvailable(GetSlot(this, EPOCHNANOSECONDS));
63+
return ES.ToBigIntExternal(JSBI.BigInt(GetSlot(this, EPOCHNANOSECONDS)));
6364
}
6465

6566
add(temporalDurationLike: Params['add'][0]): Return['add'] {
@@ -190,7 +191,7 @@ export class Instant implements Temporal.Instant {
190191
const other = ES.ToTemporalInstant(otherParam);
191192
const one = GetSlot(this, EPOCHNANOSECONDS);
192193
const two = GetSlot(other, EPOCHNANOSECONDS);
193-
return bigInt(one).equals(two);
194+
return JSBI.equal(JSBI.BigInt(one), JSBI.BigInt(two));
194195
}
195196
toString(optionsParam: Params['toString'][0] = undefined): string {
196197
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
@@ -252,23 +253,23 @@ export class Instant implements Temporal.Instant {
252253

253254
static fromEpochSeconds(epochSecondsParam: Params['fromEpochSeconds'][0]): Return['fromEpochSeconds'] {
254255
const epochSeconds = ES.ToNumber(epochSecondsParam);
255-
const epochNanoseconds = bigInt(epochSeconds).multiply(1e9);
256+
const epochNanoseconds = JSBI.multiply(JSBI.BigInt(epochSeconds), BILLION);
256257
ES.ValidateEpochNanoseconds(epochNanoseconds);
257258
return new Instant(epochNanoseconds);
258259
}
259260
static fromEpochMilliseconds(
260261
epochMillisecondsParam: Params['fromEpochMilliseconds'][0]
261262
): Return['fromEpochMilliseconds'] {
262263
const epochMilliseconds = ES.ToNumber(epochMillisecondsParam);
263-
const epochNanoseconds = bigInt(epochMilliseconds).multiply(1e6);
264+
const epochNanoseconds = JSBI.multiply(JSBI.BigInt(epochMilliseconds), MILLION);
264265
ES.ValidateEpochNanoseconds(epochNanoseconds);
265266
return new Instant(epochNanoseconds);
266267
}
267268
static fromEpochMicroseconds(
268269
epochMicrosecondsParam: Params['fromEpochMicroseconds'][0]
269270
): Return['fromEpochMicroseconds'] {
270271
const epochMicroseconds = ES.ToBigInt(epochMicrosecondsParam);
271-
const epochNanoseconds = epochMicroseconds.multiply(1e3);
272+
const epochNanoseconds = JSBI.multiply(epochMicroseconds, THOUSAND);
272273
ES.ValidateEpochNanoseconds(epochNanoseconds);
273274
return new Instant(epochNanoseconds);
274275
}
@@ -290,15 +291,11 @@ export class Instant implements Temporal.Instant {
290291
const two = ES.ToTemporalInstant(twoParam);
291292
const oneNs = GetSlot(one, EPOCHNANOSECONDS);
292293
const twoNs = GetSlot(two, EPOCHNANOSECONDS);
293-
if (bigInt(oneNs).lesser(twoNs)) return -1;
294-
if (bigInt(oneNs).greater(twoNs)) return 1;
294+
if (JSBI.lessThan(oneNs, twoNs)) return -1;
295+
if (JSBI.greaterThan(oneNs, twoNs)) return 1;
295296
return 0;
296297
}
297298
[Symbol.toStringTag]!: 'Temporal.Instant';
298299
}
299300

300301
MakeIntrinsicClass(Instant, 'Temporal.Instant');
301-
302-
function bigIntIfAvailable(wrapper: bigInt.BigInteger | bigint) {
303-
return typeof (globalThis as any).BigInt === 'undefined' ? wrapper : (wrapper as any).value;
304-
}

lib/intrinsicclass.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import bigInt from 'big-integer';
1+
import JSBI from 'jsbi';
22
import { Temporal } from '..';
33

44
import { DEBUG } from './debug';
@@ -7,10 +7,10 @@ type OmitConstructor<T> = { [P in keyof T as T[P] extends new (...args: any[]) =
77

88
type TemporalIntrinsics = Omit<typeof Temporal, 'Now' | 'Instant' | 'ZonedDateTime'> & {
99
Instant: OmitConstructor<Temporal.Instant> &
10-
(new (epochNanoseconds: bigInt.BigInteger) => Temporal.Instant) & { prototype: typeof Temporal.Instant.prototype };
10+
(new (epochNanoseconds: JSBI) => Temporal.Instant) & { prototype: typeof Temporal.Instant.prototype };
1111
ZonedDateTime: OmitConstructor<Temporal.ZonedDateTime> &
1212
(new (
13-
epochNanoseconds: bigInt.BigInteger,
13+
epochNanoseconds: JSBI,
1414
timeZone: Temporal.TimeZoneProtocol | string,
1515
calendar?: Temporal.CalendarProtocol | string
1616
) => Temporal.ZonedDateTime) & {

lib/legacydate.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import { Instant } from './instant';
22

3-
import bigInt from 'big-integer';
3+
import JSBI from 'jsbi';
4+
import * as ES from './ecmascript';
5+
import { MILLION } from './ecmascript';
46

57
export function toTemporalInstant(this: Date) {
68
// Observable access to valueOf is not correct here, but unavoidable
7-
const epochNanoseconds = bigInt(+this).multiply(1e6);
8-
return new Instant(bigIntIfAvailable(epochNanoseconds));
9-
}
10-
11-
function bigIntIfAvailable(wrapper: bigInt.BigInteger | bigint) {
12-
return typeof (globalThis as any).BigInt === 'undefined' ? wrapper : (wrapper as any).value;
9+
const epochNanoseconds = JSBI.multiply(JSBI.BigInt(+this), MILLION);
10+
return new Instant(ES.ToBigInt(epochNanoseconds));
1311
}

lib/slots.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import bigInt from 'big-integer';
1+
import JSBI from 'jsbi';
22
import type { Temporal } from '..';
33
import type { BuiltinCalendarId, AnyTemporalType } from './internaltypes';
44

@@ -54,7 +54,7 @@ interface SlotInfoRecord {
5454

5555
interface Slots extends SlotInfoRecord {
5656
// Instant
57-
[EPOCHNANOSECONDS]: SlotInfo<bigInt.BigInteger, Temporal.Instant | Temporal.ZonedDateTime>; // number? JSBI?
57+
[EPOCHNANOSECONDS]: SlotInfo<JSBI, Temporal.Instant | Temporal.ZonedDateTime>; // number? JSBI?
5858

5959
// TimeZone
6060
[TIMEZONE_ID]: SlotInfo<string, Temporal.TimeZone>;

lib/timezone.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
GetSlot,
1818
SetSlot
1919
} from './slots';
20+
import JSBI from 'jsbi';
2021
import { Temporal } from '..';
2122
import type { TimeZoneParams as Params, TimeZoneReturn as Return } from './internaltypes';
2223

@@ -97,7 +98,7 @@ export class TimeZone implements Temporal.TimeZone {
9798
GetSlot(dateTime, ISO_NANOSECOND)
9899
);
99100
if (epochNs === null) throw new RangeError('DateTime outside of supported range');
100-
return [new Instant(epochNs.minus(offsetNs))];
101+
return [new Instant(JSBI.subtract(epochNs, JSBI.BigInt(offsetNs)))];
101102
}
102103

103104
const possibleEpochNs = ES.GetIANATimeZoneEpochValue(

lib/zoneddatetime.ts

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ import { Temporal } from '..';
2020
import { DateTimeFormat } from './intl';
2121
import type { ZonedDateTimeParams as Params, ZonedDateTimeReturn as Return } from './internaltypes';
2222

23-
import bigInt from 'big-integer';
23+
import JSBI from 'jsbi';
24+
import { BILLION, MILLION, THOUSAND, ZERO } from './ecmascript';
2425

2526
const ArrayPrototypePush = Array.prototype.push;
2627

2728
export class ZonedDateTime implements Temporal.ZonedDateTime {
2829
constructor(
29-
epochNanosecondsParam: bigInt.BigInteger,
30+
epochNanosecondsParam: bigint | JSBI,
3031
timeZoneParam: Temporal.TimeZoneProtocol | string,
3132
calendarParam: Temporal.CalendarProtocol | string = ES.GetISO8601Calendar()
3233
) {
@@ -102,21 +103,21 @@ export class ZonedDateTime implements Temporal.ZonedDateTime {
102103
get epochSeconds(): Return['epochSeconds'] {
103104
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
104105
const value = GetSlot(this, EPOCHNANOSECONDS);
105-
return +value.divide(1e9);
106+
return JSBI.toNumber(JSBI.divide(value, BILLION));
106107
}
107108
get epochMilliseconds(): Return['epochMilliseconds'] {
108109
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
109110
const value = GetSlot(this, EPOCHNANOSECONDS);
110-
return +value.divide(1e6);
111+
return JSBI.toNumber(JSBI.divide(value, MILLION));
111112
}
112113
get epochMicroseconds(): Return['epochMicroseconds'] {
113114
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
114115
const value = GetSlot(this, EPOCHNANOSECONDS);
115-
return bigIntIfAvailable(value.divide(1e3));
116+
return ES.ToBigIntExternal(JSBI.divide(value, THOUSAND));
116117
}
117118
get epochNanoseconds(): Return['epochNanoseconds'] {
118119
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
119-
return bigIntIfAvailable(GetSlot(this, EPOCHNANOSECONDS));
120+
return ES.ToBigIntExternal(GetSlot(this, EPOCHNANOSECONDS));
120121
}
121122
get dayOfWeek(): Return['dayOfWeek'] {
122123
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
@@ -143,7 +144,7 @@ export class ZonedDateTime implements Temporal.ZonedDateTime {
143144
const timeZone = GetSlot(this, TIME_ZONE);
144145
const todayNs = GetSlot(ES.BuiltinTimeZoneGetInstantFor(timeZone, today, 'compatible'), EPOCHNANOSECONDS);
145146
const tomorrowNs = GetSlot(ES.BuiltinTimeZoneGetInstantFor(timeZone, tomorrow, 'compatible'), EPOCHNANOSECONDS);
146-
return tomorrowNs.subtract(todayNs).toJSNumber() / 3.6e12;
147+
return JSBI.toNumber(JSBI.subtract(tomorrowNs, todayNs)) / 3.6e12;
147148
}
148149
get daysInWeek(): Return['daysInWeek'] {
149150
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
@@ -622,8 +623,8 @@ export class ZonedDateTime implements Temporal.ZonedDateTime {
622623
const dtStart = new DateTime(GetSlot(dt, ISO_YEAR), GetSlot(dt, ISO_MONTH), GetSlot(dt, ISO_DAY), 0, 0, 0, 0, 0, 0);
623624
const instantStart = ES.BuiltinTimeZoneGetInstantFor(timeZone, dtStart, 'compatible');
624625
const endNs = ES.AddZonedDateTime(instantStart, timeZone, calendar, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);
625-
const dayLengthNs = endNs.subtract(GetSlot(instantStart, EPOCHNANOSECONDS));
626-
if (dayLengthNs.isZero()) {
626+
const dayLengthNs = JSBI.subtract(endNs, JSBI.BigInt(GetSlot(instantStart, EPOCHNANOSECONDS)));
627+
if (JSBI.equal(dayLengthNs, ZERO)) {
627628
throw new RangeError('cannot round a ZonedDateTime in a calendar with zero-length days');
628629
}
629630
({ year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = ES.RoundISODateTime(
@@ -641,7 +642,7 @@ export class ZonedDateTime implements Temporal.ZonedDateTime {
641642
roundingMode,
642643
// Days are guaranteed to be shorter than Number.MAX_SAFE_INTEGER
643644
// (which can hold up to 104 days in nanoseconds)
644-
dayLengthNs.toJSNumber()
645+
JSBI.toNumber(dayLengthNs)
645646
));
646647

647648
// Now reset all DateTime fields but leave the TimeZone. The offset will
@@ -675,7 +676,7 @@ export class ZonedDateTime implements Temporal.ZonedDateTime {
675676
const other = ES.ToTemporalZonedDateTime(otherParam);
676677
const one = GetSlot(this, EPOCHNANOSECONDS);
677678
const two = GetSlot(other, EPOCHNANOSECONDS);
678-
if (!bigInt(one).equals(two)) return false;
679+
if (!JSBI.equal(JSBI.BigInt(one), JSBI.BigInt(two))) return false;
679680
if (!ES.TimeZoneEquals(GetSlot(this, TIME_ZONE), GetSlot(other, TIME_ZONE))) return false;
680681
return ES.CalendarEquals(GetSlot(this, CALENDAR), GetSlot(other, CALENDAR));
681682
}
@@ -797,19 +798,15 @@ export class ZonedDateTime implements Temporal.ZonedDateTime {
797798
const two = ES.ToTemporalZonedDateTime(twoParam);
798799
const ns1 = GetSlot(one, EPOCHNANOSECONDS);
799800
const ns2 = GetSlot(two, EPOCHNANOSECONDS);
800-
if (bigInt(ns1).lesser(ns2)) return -1;
801-
if (bigInt(ns1).greater(ns2)) return 1;
801+
if (JSBI.lessThan(JSBI.BigInt(ns1), JSBI.BigInt(ns2))) return -1;
802+
if (JSBI.greaterThan(JSBI.BigInt(ns1), JSBI.BigInt(ns2))) return 1;
802803
return 0;
803804
}
804805
[Symbol.toStringTag]!: 'Temporal.ZonedDateTime';
805806
}
806807

807808
MakeIntrinsicClass(ZonedDateTime, 'Temporal.ZonedDateTime');
808809

809-
function bigIntIfAvailable(wrapper: bigInt.BigInteger | bigint) {
810-
return typeof (globalThis as any).BigInt === 'undefined' ? wrapper : (wrapper as any).value;
811-
}
812-
813810
function dateTime(zdt: Temporal.ZonedDateTime) {
814811
return ES.BuiltinTimeZoneGetPlainDateTimeFor(GetSlot(zdt, TIME_ZONE), GetSlot(zdt, INSTANT), GetSlot(zdt, CALENDAR));
815812
}

package-lock.json

Lines changed: 13 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)