blob: d952ed1f9b4ef54561a912cb08c2320c4e144fb9 [file] [log] [blame]
//@ requireOptions("--useTemporal=1")
function shouldBe(actual, expected) {
if (actual !== expected)
throw new Error(`expected ${expected} but got ${actual}`);
}
function shouldNotBe(actual, expected) {
if (actual === expected)
throw new Error(`expected a value to be different from ${expected}`);
}
function shouldThrow(func, errorType, message) {
let error;
try {
func();
} catch (e) {
error = e;
}
if (!(error instanceof errorType))
throw new Error(`Expected ${errorType.name}!`);
if (message !== undefined) {
if (Object.prototype.toString.call(message) === '[object RegExp]') {
if (!message.test(String(error)))
throw new Error(`expected '${String(error)}' to match ${message}!`);
} else {
shouldBe(String(error), message);
}
}
}
// epoch
{
const instants = [
new Temporal.Instant(0n),
Temporal.Instant.fromEpochSeconds(0),
Temporal.Instant.fromEpochMilliseconds(0),
Temporal.Instant.fromEpochMicroseconds(0n),
Temporal.Instant.fromEpochNanoseconds(0n),
Temporal.Instant.from('1970-01-01T00:00:00Z'),
];
instants.forEach((instant) => {
shouldBe(instant.epochSeconds, 0);
shouldBe(instant.epochMilliseconds, 0);
shouldBe(instant.epochMicroseconds, 0n);
shouldBe(instant.epochNanoseconds, 0n);
shouldBe(instant.toString(), '1970-01-01T00:00:00Z');
shouldBe(instant.toJSON(), '1970-01-01T00:00:00Z');
});
}
// positive epoch value
{
const instants = [
new Temporal.Instant(1_000_000_000_000_000_000n),
Temporal.Instant.fromEpochSeconds(1_000_000_000),
Temporal.Instant.fromEpochMilliseconds(1_000_000_000_000),
Temporal.Instant.fromEpochMicroseconds(1_000_000_000_000_000n),
Temporal.Instant.fromEpochNanoseconds(1_000_000_000_000_000_000n),
Temporal.Instant.from('2001-09-09T01:46:40Z'),
];
instants.forEach((instant) => {
shouldBe(instant.epochSeconds, 1_000_000_000);
shouldBe(instant.epochMilliseconds, 1_000_000_000_000);
shouldBe(instant.epochMicroseconds, 1_000_000_000_000_000n);
shouldBe(instant.epochNanoseconds, 1_000_000_000_000_000_000n);
shouldBe(instant.toString(), '2001-09-09T01:46:40Z');
shouldBe(instant.toJSON(), '2001-09-09T01:46:40Z');
});
}
// negative epoch value
{
const instants = [
new Temporal.Instant(-1_000_000_000_000_000_000n),
Temporal.Instant.fromEpochSeconds(-1_000_000_000),
Temporal.Instant.fromEpochMilliseconds(-1_000_000_000_000),
Temporal.Instant.fromEpochMicroseconds(-1_000_000_000_000_000n),
Temporal.Instant.fromEpochNanoseconds(-1_000_000_000_000_000_000n),
Temporal.Instant.from('1938-04-24T22:13:20Z'),
];
instants.forEach((instant) => {
shouldBe(instant.epochSeconds, -1_000_000_000);
shouldBe(instant.epochMilliseconds, -1_000_000_000_000);
shouldBe(instant.epochMicroseconds, -1_000_000_000_000_000n);
shouldBe(instant.epochNanoseconds, -1_000_000_000_000_000_000n);
shouldBe(instant.toString(), '1938-04-24T22:13:20Z');
shouldBe(instant.toJSON(), '1938-04-24T22:13:20Z');
});
}
// maxint64 epoch value
{
const instants = [
new Temporal.Instant(9223372036854775807n),
Temporal.Instant.fromEpochNanoseconds(9223372036854775807n),
Temporal.Instant.from('2262-04-11T23:47:16.854775807Z'),
];
instants.forEach((instant) => {
shouldBe(instant.epochSeconds, 9223372036);
shouldBe(instant.epochMilliseconds, 9223372036854);
shouldBe(instant.epochMicroseconds, 9223372036854775n);
shouldBe(instant.epochNanoseconds, 9223372036854775807n);
shouldBe(instant.toString(), '2262-04-11T23:47:16.854775807Z');
shouldBe(instant.toJSON(), '2262-04-11T23:47:16.854775807Z');
});
}
// minint64 epoch value
{
const instants = [
new Temporal.Instant(-9223372036854775808n),
Temporal.Instant.fromEpochNanoseconds(-9223372036854775808n),
Temporal.Instant.from('1677-09-21T00:12:43.145224192Z'),
];
instants.forEach((instant) => {
shouldBe(instant.epochSeconds, -9223372036);
shouldBe(instant.epochMilliseconds, -9223372036854);
shouldBe(instant.epochMicroseconds, -9223372036854775n);
shouldBe(instant.epochNanoseconds, -9223372036854775808n);
shouldBe(instant.toString(), '1677-09-21T00:12:43.145224192Z');
shouldBe(instant.toJSON(), '1677-09-21T00:12:43.145224192Z');
});
}
// max Instant range
{
const instants = [
new Temporal.Instant(86400_0000_0000_000_000_000n),
Temporal.Instant.fromEpochSeconds(86400_0000_0000),
Temporal.Instant.fromEpochMilliseconds(86400_0000_0000_000),
Temporal.Instant.fromEpochMicroseconds(86400_0000_0000_000_000n),
Temporal.Instant.fromEpochNanoseconds(86400_0000_0000_000_000_000n),
Temporal.Instant.from('+275760-09-13T00:00:00Z'),
];
instants.forEach((instant) => {
shouldBe(instant.epochSeconds, 86400_0000_0000);
shouldBe(instant.epochMilliseconds, 86400_0000_0000_000);
shouldBe(instant.epochMicroseconds, 86400_0000_0000_000_000n);
shouldBe(instant.epochNanoseconds, 86400_0000_0000_000_000_000n);
shouldBe(instant.toString(), '+275760-09-13T00:00:00Z');
shouldBe(instant.toJSON(), '+275760-09-13T00:00:00Z');
});
}
// min Instant range
{
const instants = [
new Temporal.Instant(-86400_0000_0000_000_000_000n),
Temporal.Instant.fromEpochSeconds(-86400_0000_0000),
Temporal.Instant.fromEpochMilliseconds(-86400_0000_0000_000),
Temporal.Instant.fromEpochMicroseconds(-86400_0000_0000_000_000n),
Temporal.Instant.fromEpochNanoseconds(-86400_0000_0000_000_000_000n),
Temporal.Instant.from('-271821-04-20T00:00:00Z'),
];
instants.forEach((instant) => {
shouldBe(instant.epochSeconds, -86400_0000_0000);
shouldBe(instant.epochMilliseconds, -86400_0000_0000_000);
shouldBe(instant.epochMicroseconds, -86400_0000_0000_000_000n);
shouldBe(instant.epochNanoseconds, -86400_0000_0000_000_000_000n);
shouldBe(instant.toString(), '-271821-04-20T00:00:00Z');
shouldBe(instant.toJSON(), '-271821-04-20T00:00:00Z');
});
}
[
// too large
[86400_0000_0000_000_000_001n, /\b8640000000000000000001\b/],
// too small
[-86400_0000_0000_000_000_001n, /-8640000000000000000001\b/],
// test -minint128 specifically
[1n << 128n, /\b340282366920938463463374607431768211456\b/],
// much larger than maxint128
[1n << 129n, /\b680564733841876926926749214863536422912\b/],
// smaller than minint128
[-1n << 129n, /-680564733841876926926749214863536422912\b/],
// behaves sensibly even when the bigint is really long
[BigInt('9'.repeat(1000))],
].forEach(([ns, messageMatch = undefined]) => {
shouldThrow(() => new Temporal.Instant(ns), RangeError, messageMatch);
shouldThrow(() => Temporal.Instant.fromEpochNanoseconds(ns), RangeError, messageMatch);
});
[
// too large
[86400_0000_0000_000_001n, /\b8640000000000000001\b/],
// too small
[-86400_0000_0000_000_001n, /-8640000000000000001\b/],
// test maxuint64 specifically
[1n << 64n, /\b18446744073709551616\b/],
// test maxuint128 specifically
[1n << 128n, /\b340282366920938463463374607431768211456\b/],
// much larger than maxint128
[1n << 129n, /\b680564733841876926926749214863536422912\b/],
// smaller than minint128
[-1n << 129n, /-680564733841876926926749214863536422912\b/],
// behaves sensibly even when the bigint is really long
[BigInt('9'.repeat(1000))],
].forEach(([µs, messageMatch = undefined]) => {
shouldThrow(() => Temporal.Instant.fromEpochMicroseconds(µs), RangeError, messageMatch);
});
// constructs from string
shouldBe(new Temporal.Instant('0').epochNanoseconds, 0n);
// throws on number
shouldThrow(() => new Temporal.Instant(0), TypeError);
// throws on string that does not convert to BigInt
shouldThrow(() => new Temporal.Instant('abc123'), SyntaxError);
// Instant.from(instant) is not the same object
{
const inst = Temporal.Instant.from('2020-02-12T11:42+01:00[Europe/Amsterdam]');
shouldNotBe(Temporal.Instant.from(inst), inst);
}
// toString
{
const i1 = Temporal.Instant.from('1976-11-18T15:23Z');
const i2 = Temporal.Instant.from('1976-11-18T15:23:30Z');
const i3 = Temporal.Instant.from('1976-11-18T15:23:30.1234Z');
// default is to emit seconds and drop trailing zeros after the decimal'
shouldBe(i1.toString(), '1976-11-18T15:23:00Z');
shouldBe(i2.toString(), '1976-11-18T15:23:30Z');
shouldBe(i3.toString(), '1976-11-18T15:23:30.1234Z');
// truncates to minute
[i1, i2, i3].forEach((i) => shouldBe(i.toString({ smallestUnit: 'minute' }), '1976-11-18T15:23Z'));
// other smallestUnits are aliases for fractional digits
shouldBe(i3.toString({ smallestUnit: 'second' }), i3.toString({ fractionalSecondDigits: 0 }));
shouldBe(i3.toString({ smallestUnit: 'millisecond' }), i3.toString({ fractionalSecondDigits: 3 }));
shouldBe(i3.toString({ smallestUnit: 'microsecond' }), i3.toString({ fractionalSecondDigits: 6 }));
shouldBe(i3.toString({ smallestUnit: 'nanosecond' }), i3.toString({ fractionalSecondDigits: 9 }));
// truncate or pad to 2 places
{
const options = { fractionalSecondDigits: 2 };
shouldBe(i1.toString(options), '1976-11-18T15:23:00.00Z');
shouldBe(i2.toString(options), '1976-11-18T15:23:30.00Z');
shouldBe(i3.toString(options), '1976-11-18T15:23:30.12Z');
}
// pad to 7 places
{
const options = { fractionalSecondDigits: 7 };
shouldBe(i1.toString(options), '1976-11-18T15:23:00.0000000Z');
shouldBe(i2.toString(options), '1976-11-18T15:23:30.0000000Z');
shouldBe(i3.toString(options), '1976-11-18T15:23:30.1234000Z');
}
// round to nearest
shouldBe(i2.toString({ smallestUnit: 'minute', roundingMode: 'halfExpand' }), '1976-11-18T15:24Z');
shouldBe(i3.toString({ fractionalSecondDigits: 3, roundingMode: 'halfExpand' }), '1976-11-18T15:23:30.123Z');
// round up
shouldBe(i2.toString({ smallestUnit: 'minute', roundingMode: 'ceil' }), '1976-11-18T15:24Z');
shouldBe(i3.toString({ fractionalSecondDigits: 3, roundingMode: 'ceil' }), '1976-11-18T15:23:30.124Z');
// round down
['floor', 'trunc'].forEach((roundingMode) => {
shouldBe(i2.toString({ smallestUnit: 'minute', roundingMode }), '1976-11-18T15:23Z');
shouldBe(i3.toString({ fractionalSecondDigits: 3, roundingMode }), '1976-11-18T15:23:30.123Z');
});
{
// rounding down is towards the Big Bang, not towards 1 BCE
const i4 = Temporal.Instant.from('-000099-12-15T12:00:00.5Z');
shouldBe(i4.toString({ smallestUnit: 'second', roundingMode: 'floor' }), '-000099-12-15T12:00:00Z');
// rounding can affect all units
const i5 = Temporal.Instant.from('1999-12-31T23:59:59.999999999Z');
shouldBe(i5.toString({ fractionalSecondDigits: 8, roundingMode: 'halfExpand' }), '2000-01-01T00:00:00.00000000Z');
}
}
// leap second is constrained
shouldBe(`${Temporal.Instant.from('2016-12-31T23:59:60Z')}`, '2016-12-31T23:59:59Z');
// variant time separators
shouldBe(`${Temporal.Instant.from('1976-11-18 15:23Z')}`, '1976-11-18T15:23:00Z');
shouldBe(`${Temporal.Instant.from('1976-11-18t15:23Z')}`, '1976-11-18T15:23:00Z');
// variant UTC designator
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23z')}`, '1976-11-18T15:23:00Z');
// any number of decimal places
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.1Z')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.12Z')}`, '1976-11-18T15:23:30.12Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.123Z')}`, '1976-11-18T15:23:30.123Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.1234Z')}`, '1976-11-18T15:23:30.1234Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.12345Z')}`, '1976-11-18T15:23:30.12345Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.123456Z')}`, '1976-11-18T15:23:30.123456Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.1234567Z')}`, '1976-11-18T15:23:30.1234567Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.12345678Z')}`, '1976-11-18T15:23:30.12345678Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.123456789Z')}`, '1976-11-18T15:23:30.123456789Z');
// variant decimal separator
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30,12Z')}`, '1976-11-18T15:23:30.12Z');
// variant minus sign
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.12\u221202:00')}`, '1976-11-18T17:23:30.12Z');
shouldBe(`${Temporal.Instant.from('\u2212009999-11-18T15:23:30.12Z')}`, '-009999-11-18T15:23:30.12Z');
// mixture of basic and extended format
shouldBe(`${Temporal.Instant.from('19761118T15:23:30.1+00:00')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T152330.1+00:00')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.1+0000')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T152330.1+0000')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('19761118T15:23:30.1+0000')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('19761118T152330.1+00:00')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('+0019761118T15:23:30.1+00:00')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('+001976-11-18T152330.1+00:00')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('+001976-11-18T15:23:30.1+0000')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('+001976-11-18T152330.1+0000')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('+0019761118T15:23:30.1+0000')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('+0019761118T152330.1+00:00')}`, '1976-11-18T15:23:30.1Z');
shouldBe(`${Temporal.Instant.from('+0019761118T152330.1+0000')}`, '1976-11-18T15:23:30.1Z');
// optional parts
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30+00')}`, '1976-11-18T15:23:30Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T15Z')}`, '1976-11-18T15:00:00Z');
// ignores any specified calendar
// FIXME: parse calendar
// shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.123456789Z[u-ca=discord]')}`, '1976-11-18T15:23:30.123456789Z');
// no junk at end of string
shouldThrow(() => Temporal.Instant.from('1976-11-18T15:23:30.123456789Zjunk'), RangeError);
// For convenience in several tests
const epoch = new Temporal.Instant(0n);
const minValue = new Temporal.Instant(-86400_0000_0000_000_000_000n);
const maxValue = new Temporal.Instant(86400_0000_0000_000_000_000n);
// add()
{
shouldBe(epoch.add({ hours: 1 }).epochNanoseconds, 3600_000_000_000n);
shouldBe(epoch.add({ hours: -1 }).epochNanoseconds, -3600_000_000_000n);
shouldBe(epoch.add({ minutes: 1 }).epochNanoseconds, 60_000_000_000n);
shouldBe(epoch.add({ minutes: -1 }).epochNanoseconds, -60_000_000_000n);
shouldBe(epoch.add({ seconds: 1 }).epochNanoseconds, 1_000_000_000n);
shouldBe(epoch.add({ seconds: -1 }).epochNanoseconds, -1_000_000_000n);
shouldBe(epoch.add({ milliseconds: 1 }).epochNanoseconds, 1_000_000n);
shouldBe(epoch.add({ milliseconds: -1 }).epochNanoseconds, -1_000_000n);
shouldBe(epoch.add({ microseconds: 1 }).epochNanoseconds, 1_000n);
shouldBe(epoch.add({ microseconds: -1 }).epochNanoseconds, -1_000n);
shouldBe(epoch.add({ nanoseconds: 1 }).epochNanoseconds, 1n);
shouldBe(epoch.add({ nanoseconds: -1 }).epochNanoseconds, -1n);
}
{
// max duration that can be added to any Instant
shouldBe(minValue.add({ hours: 48_0000_0000 }).epochNanoseconds, maxValue.epochNanoseconds);
shouldBe(maxValue.add({ hours: -48_0000_0000 }).epochNanoseconds, minValue.epochNanoseconds);
shouldBe(minValue.add({ minutes: 2880_0000_0000 }).epochNanoseconds, maxValue.epochNanoseconds);
shouldBe(maxValue.add({ minutes: -2880_0000_0000 }).epochNanoseconds, minValue.epochNanoseconds);
shouldBe(minValue.add({ seconds: 172800_0000_0000 }).epochNanoseconds, maxValue.epochNanoseconds);
shouldBe(maxValue.add({ seconds: -172800_0000_0000 }).epochNanoseconds, minValue.epochNanoseconds);
// note, unsafe integers from here on; the multiplication to convert
// milliseconds and microseconds to nanoseconds should take place in the
// bigint domain.
shouldBe(minValue.add({ milliseconds: 172800_0000_0000_000 }).epochNanoseconds, maxValue.epochNanoseconds);
shouldBe(maxValue.add({ milliseconds: -172800_0000_0000_000 }).epochNanoseconds, minValue.epochNanoseconds);
shouldBe(minValue.add({ microseconds: 172800_0000_0000_000_000 }).epochNanoseconds, maxValue.epochNanoseconds);
shouldBe(maxValue.add({ microseconds: -172800_0000_0000_000_000 }).epochNanoseconds, minValue.epochNanoseconds);
shouldBe(minValue.add({ nanoseconds: 172800_0000_0000_000_000_000 }).epochNanoseconds, maxValue.epochNanoseconds);
shouldBe(maxValue.add({ nanoseconds: -172800_0000_0000_000_000_000 }).epochNanoseconds, minValue.epochNanoseconds);
}
{
// overflowing 64 bits
const exp64 = 2 ** 64;
['hours', 'minutes', 'seconds', 'milliseconds', 'microseconds'].forEach((unit) => {
shouldThrow(() => epoch.add({ [unit]: exp64 }), RangeError);
shouldThrow(() => epoch.add({ [unit]: -exp64 }), RangeError);
});
shouldBe(epoch.add({ nanoseconds: exp64 }).epochNanoseconds, 18446744073709551616n);
shouldBe(epoch.add({ nanoseconds: -exp64 }).epochNanoseconds, -18446744073709551616n);
}
{
// overflowing 128 bits
['hours', 'minutes', 'seconds', 'milliseconds', 'microseconds', 'nanoseconds'].forEach((unit) => {
shouldThrow(() => epoch.add({ [unit]: Number.MAX_VALUE }), RangeError);
shouldThrow(() => epoch.add({ [unit]: -Number.MAX_VALUE }), RangeError);
});
}
// subtract()
{
shouldBe(epoch.subtract({ hours: 1 }).epochNanoseconds, -3600_000_000_000n);
shouldBe(epoch.subtract({ hours: -1 }).epochNanoseconds, 3600_000_000_000n);
shouldBe(epoch.subtract({ minutes: 1 }).epochNanoseconds, -60_000_000_000n);
shouldBe(epoch.subtract({ minutes: -1 }).epochNanoseconds, 60_000_000_000n);
shouldBe(epoch.subtract({ seconds: 1 }).epochNanoseconds, -1_000_000_000n);
shouldBe(epoch.subtract({ seconds: -1 }).epochNanoseconds, 1_000_000_000n);
shouldBe(epoch.subtract({ milliseconds: 1 }).epochNanoseconds, -1_000_000n);
shouldBe(epoch.subtract({ milliseconds: -1 }).epochNanoseconds, 1_000_000n);
shouldBe(epoch.subtract({ microseconds: 1 }).epochNanoseconds, -1_000n);
shouldBe(epoch.subtract({ microseconds: -1 }).epochNanoseconds, 1_000n);
shouldBe(epoch.subtract({ nanoseconds: 1 }).epochNanoseconds, -1n);
shouldBe(epoch.subtract({ nanoseconds: -1 }).epochNanoseconds, 1n);
}
{
// max duration that can be added to any Instant
shouldBe(maxValue.subtract({ hours: 48_0000_0000 }).epochNanoseconds, minValue.epochNanoseconds);
shouldBe(minValue.subtract({ hours: -48_0000_0000 }).epochNanoseconds, maxValue.epochNanoseconds);
shouldBe(maxValue.subtract({ minutes: 2880_0000_0000 }).epochNanoseconds, minValue.epochNanoseconds);
shouldBe(minValue.subtract({ minutes: -2880_0000_0000 }).epochNanoseconds, maxValue.epochNanoseconds);
shouldBe(maxValue.subtract({ seconds: 172800_0000_0000 }).epochNanoseconds, minValue.epochNanoseconds);
shouldBe(minValue.subtract({ seconds: -172800_0000_0000 }).epochNanoseconds, maxValue.epochNanoseconds);
// note, unsafe integers from here on; the multiplication to convert
// milliseconds and microseconds to nanoseconds should take place in the
// bigint domain.
shouldBe(maxValue.subtract({ milliseconds: 172800_0000_0000_000 }).epochNanoseconds, minValue.epochNanoseconds);
shouldBe(minValue.subtract({ milliseconds: -172800_0000_0000_000 }).epochNanoseconds, maxValue.epochNanoseconds);
shouldBe(maxValue.subtract({ microseconds: 172800_0000_0000_000_000 }).epochNanoseconds, minValue.epochNanoseconds);
shouldBe(minValue.subtract({ microseconds: -172800_0000_0000_000_000 }).epochNanoseconds, maxValue.epochNanoseconds);
shouldBe(maxValue.subtract({ nanoseconds: 172800_0000_0000_000_000_000 }).epochNanoseconds, minValue.epochNanoseconds);
shouldBe(minValue.subtract({ nanoseconds: -172800_0000_0000_000_000_000 }).epochNanoseconds, maxValue.epochNanoseconds);
}
{
// overflowing 64 bits
const exp64 = 2 ** 64;
['hours', 'minutes', 'seconds', 'milliseconds', 'microseconds'].forEach((unit) => {
shouldThrow(() => epoch.subtract({ [unit]: exp64 }), RangeError);
shouldThrow(() => epoch.subtract({ [unit]: -exp64 }), RangeError);
});
shouldBe(epoch.subtract({ nanoseconds: exp64 }).epochNanoseconds, -18446744073709551616n);
shouldBe(epoch.subtract({ nanoseconds: -exp64 }).epochNanoseconds, 18446744073709551616n);
}
{
// overflowing 128 bits
['hours', 'minutes', 'seconds', 'milliseconds', 'microseconds', 'nanoseconds'].forEach((unit) => {
shouldThrow(() => epoch.subtract({ [unit]: Number.MAX_VALUE }), RangeError);
shouldThrow(() => epoch.subtract({ [unit]: -Number.MAX_VALUE }), RangeError);
});
}