@fable-org/fable-library-js 2.6.0 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -1
- package/DateOnlyTemporal.js +146 -0
- package/DateTimeFormat.js +523 -0
- package/DateTimeOffsetTemporal.js +283 -0
- package/DateTimeTemporal.js +243 -0
- package/Guid.js +3 -1
- package/Numeric.js +38 -1
- package/String.js +39 -9
- package/TimeOnlyTemporal.js +142 -0
- package/TimeSpanTemporal.js +259 -0
- package/lib/big.js +14 -10
- package/package.json +1 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { toInt64, fromFloat64 } from "./BigInt.js";
|
|
2
|
+
import { fromTicks as TimeSpan_fromTicks, totalNanoseconds as TimeSpan_totalNanoseconds } from "./TimeSpanTemporal.js";
|
|
3
|
+
import { Exception } from "./Util.js";
|
|
4
|
+
export const PlainTime = Temporal.PlainTime;
|
|
5
|
+
// The generic equality/comparison/hashing helpers in Util.ts dispatch at runtime
|
|
6
|
+
// on .NET-style Equals/CompareTo/GetHashCode methods. Attach them so TimeOnly
|
|
7
|
+
// also works in generic contexts: records, tuples, erased generics, etc.
|
|
8
|
+
const proto = Temporal.PlainTime.prototype;
|
|
9
|
+
proto.Equals = function (other) { return this.equals(other); };
|
|
10
|
+
proto.CompareTo = function (other) { return Temporal.PlainTime.compare(this, other); };
|
|
11
|
+
proto.GetHashCode = function () { return hash(this); };
|
|
12
|
+
// Lets String.Format format this value without String.ts importing this module (see String.ts)
|
|
13
|
+
proto[Symbol.for("Fable.DateTimeFormattable")] = function (format) { return toString(this, format); };
|
|
14
|
+
const nanosecondsPerDay = 86400000000000;
|
|
15
|
+
const nanosecondsPerDayBig = 86400000000000n;
|
|
16
|
+
function totalNanoseconds(t) {
|
|
17
|
+
return ((t.hour * 60 + t.minute) * 60 + t.second) * 1000000000
|
|
18
|
+
+ t.millisecond * 1000000 + t.microsecond * 1000 + t.nanosecond;
|
|
19
|
+
}
|
|
20
|
+
function fromNanoseconds(n) {
|
|
21
|
+
return new Temporal.PlainTime(Math.floor(n / 3600000000000), Math.floor(n / 60000000000) % 60, Math.floor(n / 1000000000) % 60, Math.floor(n / 1000000) % 1000, Math.floor(n / 1000) % 1000, n % 1000);
|
|
22
|
+
}
|
|
23
|
+
export function create(h = 0, m = 0, s = 0, ms = 0, us = 0) {
|
|
24
|
+
return new Temporal.PlainTime(h, m, s, ms, us);
|
|
25
|
+
}
|
|
26
|
+
export function fromTicks(ticks) {
|
|
27
|
+
return fromNanoseconds(Number(BigInt(ticks) * 100n));
|
|
28
|
+
}
|
|
29
|
+
export function fromTimeSpan(timeSpan) {
|
|
30
|
+
const ns = Number(TimeSpan_totalNanoseconds(timeSpan));
|
|
31
|
+
if (ns < 0 || ns >= nanosecondsPerDay)
|
|
32
|
+
throw new Exception("The TimeSpan describes an unrepresentable TimeOnly.");
|
|
33
|
+
return fromNanoseconds(ns);
|
|
34
|
+
}
|
|
35
|
+
export function fromDateTime(d) {
|
|
36
|
+
// Under the Temporal representation a DateTime is a PlainDateTime (kind-agnostic wall-clock)
|
|
37
|
+
return new Temporal.PlainTime(d.hour, d.minute, d.second, d.millisecond, d.microsecond, d.nanosecond);
|
|
38
|
+
}
|
|
39
|
+
export function minValue() {
|
|
40
|
+
return new Temporal.PlainTime();
|
|
41
|
+
}
|
|
42
|
+
export function maxValue() {
|
|
43
|
+
// This is "23:59:59.9999999" (.NET tick precision)
|
|
44
|
+
return new Temporal.PlainTime(23, 59, 59, 999, 999, 900);
|
|
45
|
+
}
|
|
46
|
+
export function ticks(t) {
|
|
47
|
+
return toInt64(fromFloat64(totalNanoseconds(t) / 100));
|
|
48
|
+
}
|
|
49
|
+
export function toTimeSpan(t) {
|
|
50
|
+
// TimeOnly is tick-precise, so the nanosecond count is always a multiple of 100.
|
|
51
|
+
return TimeSpan_fromTicks(Math.round(totalNanoseconds(t) / 100));
|
|
52
|
+
}
|
|
53
|
+
// Kept in bigint: a TimeOnly itself always fits a float64 exactly (under 2^47 ns),
|
|
54
|
+
// but the amount added does not — a TimeSpan of more than ~104 days already
|
|
55
|
+
// exceeds Number.MAX_SAFE_INTEGER in nanoseconds, and .NET wraps it modulo a day
|
|
56
|
+
// rather than saturating, so the low ticks are the part that must survive.
|
|
57
|
+
function addNanoseconds(t, deltaNs, wrappedDays) {
|
|
58
|
+
const totalNs = BigInt(totalNanoseconds(t)) + deltaNs;
|
|
59
|
+
let days = totalNs / nanosecondsPerDayBig;
|
|
60
|
+
let remainder = totalNs % nanosecondsPerDayBig;
|
|
61
|
+
// BigInt division truncates toward zero; .NET wraps toward the previous day.
|
|
62
|
+
if (remainder < 0n) {
|
|
63
|
+
remainder += nanosecondsPerDayBig;
|
|
64
|
+
days -= 1n;
|
|
65
|
+
}
|
|
66
|
+
if (wrappedDays !== undefined) {
|
|
67
|
+
wrappedDays.contents = Number(days);
|
|
68
|
+
}
|
|
69
|
+
return fromNanoseconds(Number(remainder));
|
|
70
|
+
}
|
|
71
|
+
export function add(t, ts, wrappedDays) {
|
|
72
|
+
return addNanoseconds(t, TimeSpan_totalNanoseconds(ts), wrappedDays);
|
|
73
|
+
}
|
|
74
|
+
export function addHours(t, h) {
|
|
75
|
+
// Scale to ticks first, as .NET does, then widen — `h` hours in nanoseconds
|
|
76
|
+
// overflows the exact float64 range two orders of magnitude sooner.
|
|
77
|
+
return addNanoseconds(t, BigInt(Math.round(h * 36000000000)) * 100n);
|
|
78
|
+
}
|
|
79
|
+
export function addMinutes(t, m) {
|
|
80
|
+
return addNanoseconds(t, BigInt(Math.round(m * 600000000)) * 100n);
|
|
81
|
+
}
|
|
82
|
+
export function isBetween(t, start, end) {
|
|
83
|
+
return Temporal.PlainTime.compare(start, end) <= 0
|
|
84
|
+
? (Temporal.PlainTime.compare(start, t) <= 0 && Temporal.PlainTime.compare(end, t) > 0)
|
|
85
|
+
: (Temporal.PlainTime.compare(start, t) <= 0 || Temporal.PlainTime.compare(end, t) > 0);
|
|
86
|
+
}
|
|
87
|
+
export function equals(x, y) {
|
|
88
|
+
return x.equals(y);
|
|
89
|
+
}
|
|
90
|
+
export function compare(x, y) {
|
|
91
|
+
return Temporal.PlainTime.compare(x, y);
|
|
92
|
+
}
|
|
93
|
+
export function hash(t) {
|
|
94
|
+
return totalNanoseconds(t) % 2147483647;
|
|
95
|
+
}
|
|
96
|
+
export function op_Subtraction(left, right) {
|
|
97
|
+
// Returns the elapsed TimeSpan, wrapping around midnight
|
|
98
|
+
const ns = (totalNanoseconds(left) - totalNanoseconds(right) + nanosecondsPerDay) % nanosecondsPerDay;
|
|
99
|
+
return TimeSpan_fromTicks(Math.round(ns / 100));
|
|
100
|
+
}
|
|
101
|
+
export function toString(t, format = "t", _provider) {
|
|
102
|
+
switch (format) {
|
|
103
|
+
case "t":
|
|
104
|
+
return t.toString({ smallestUnit: "minute" });
|
|
105
|
+
case "r":
|
|
106
|
+
case "R":
|
|
107
|
+
case "T":
|
|
108
|
+
return t.toString({ smallestUnit: "second" });
|
|
109
|
+
case "o":
|
|
110
|
+
case "O":
|
|
111
|
+
// .NET tick precision is 7 fractional digits
|
|
112
|
+
return t.toString({ fractionalSecondDigits: 7 });
|
|
113
|
+
default:
|
|
114
|
+
throw new Exception("Custom formats are not supported");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export function parse(str) {
|
|
118
|
+
// Allowed format types:
|
|
119
|
+
// hh:mm
|
|
120
|
+
// hh:mm:ss
|
|
121
|
+
// hh:mm:ss.fffffff
|
|
122
|
+
const r = /^\s*([0-1]?\d|2[0-3])\s*:\s*([0-5]?\d)(\s*:\s*([0-5]?\d)(\.(\d+))?)?\s*$/.exec(str);
|
|
123
|
+
if (r != null && r[1] != null && r[2] != null) {
|
|
124
|
+
const h = +r[1];
|
|
125
|
+
const m = +r[2];
|
|
126
|
+
const s = r[4] != null ? +r[4] : 0;
|
|
127
|
+
// .NET resolves the fraction down to a single tick (7 digits) and truncates
|
|
128
|
+
// anything finer, so the digits are read as ticks rather than milliseconds.
|
|
129
|
+
const subSecondTicks = r[6] != null ? +r[6].padEnd(7, "0").substring(0, 7) : 0;
|
|
130
|
+
return fromNanoseconds(((h * 60 + m) * 60 + s) * 1000000000 + subSecondTicks * 100);
|
|
131
|
+
}
|
|
132
|
+
throw new Exception(`String '${str}' was not recognized as a valid TimeOnly.`);
|
|
133
|
+
}
|
|
134
|
+
export function tryParse(v, defValue) {
|
|
135
|
+
try {
|
|
136
|
+
defValue.contents = parse(v);
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { toInt64 } from "./BigInt.js";
|
|
2
|
+
import { Exception, padWithZeros } from "./Util.js";
|
|
3
|
+
export const Duration = Temporal.Duration;
|
|
4
|
+
// The generic equality/comparison/hashing helpers in Util.ts dispatch at runtime
|
|
5
|
+
// on .NET-style Equals/CompareTo/GetHashCode methods. Attach them so TimeSpan
|
|
6
|
+
// also works in generic contexts: records, tuples, erased generics, etc.
|
|
7
|
+
const proto = Temporal.Duration.prototype;
|
|
8
|
+
proto.Equals = function (other) { return Temporal.Duration.compare(this, other) === 0; };
|
|
9
|
+
proto.CompareTo = function (other) { return Temporal.Duration.compare(this, other); };
|
|
10
|
+
proto.GetHashCode = function () { return hash(this); };
|
|
11
|
+
// Lets String.Format format this value without String.ts importing this module (see String.ts)
|
|
12
|
+
proto[Symbol.for("Fable.DateTimeFormattable")] = function (format) { return toString(this, format); };
|
|
13
|
+
const nsPerMillisecond = 1000000n;
|
|
14
|
+
const nsPerSecond = 1000000000n;
|
|
15
|
+
const nsPerMinute = 60000000000n;
|
|
16
|
+
const nsPerHour = 3600000000000n;
|
|
17
|
+
const nsPerDay = 86400000000000n;
|
|
18
|
+
export function totalNanoseconds(ts) {
|
|
19
|
+
return BigInt(ts.days) * nsPerDay
|
|
20
|
+
+ BigInt(ts.hours) * nsPerHour
|
|
21
|
+
+ BigInt(ts.minutes) * nsPerMinute
|
|
22
|
+
+ BigInt(ts.seconds) * nsPerSecond
|
|
23
|
+
+ BigInt(ts.milliseconds) * nsPerMillisecond
|
|
24
|
+
+ BigInt(ts.microseconds) * 1000n
|
|
25
|
+
+ BigInt(ts.nanoseconds);
|
|
26
|
+
}
|
|
27
|
+
function fromNanoseconds(totalNs) {
|
|
28
|
+
const negative = totalNs < 0n;
|
|
29
|
+
// A .NET TimeSpan is a whole number of 100ns ticks, so anything finer than a
|
|
30
|
+
// tick is dropped (toward zero, as .NET does) rather than carried in the
|
|
31
|
+
// Duration's nanosecond field — otherwise values that cannot exist in .NET
|
|
32
|
+
// would leak out of Parse/FromMilliseconds/arithmetic.
|
|
33
|
+
let n = (negative ? -totalNs : totalNs) / 100n * 100n;
|
|
34
|
+
const days = Number(n / nsPerDay);
|
|
35
|
+
n %= nsPerDay;
|
|
36
|
+
const hours = Number(n / nsPerHour);
|
|
37
|
+
n %= nsPerHour;
|
|
38
|
+
const minutes = Number(n / nsPerMinute);
|
|
39
|
+
n %= nsPerMinute;
|
|
40
|
+
const seconds = Number(n / nsPerSecond);
|
|
41
|
+
n %= nsPerSecond;
|
|
42
|
+
const milliseconds = Number(n / nsPerMillisecond);
|
|
43
|
+
n %= nsPerMillisecond;
|
|
44
|
+
const microseconds = Number(n / 1000n);
|
|
45
|
+
n %= 1000n;
|
|
46
|
+
const d = new Temporal.Duration(0, 0, 0, days, hours, minutes, seconds, milliseconds, microseconds, Number(n));
|
|
47
|
+
return negative ? d.negated() : d;
|
|
48
|
+
}
|
|
49
|
+
// Converts a possibly fractional unit count into an exact nanosecond amount,
|
|
50
|
+
// keeping the integer part exact for the full Int64 tick range.
|
|
51
|
+
function unitToNanoseconds(value, nsPerUnit) {
|
|
52
|
+
const whole = Math.trunc(value);
|
|
53
|
+
const frac = value - whole;
|
|
54
|
+
return BigInt(whole) * nsPerUnit + BigInt(Math.round(frac * Number(nsPerUnit)));
|
|
55
|
+
}
|
|
56
|
+
export function create(d = 0, h = 0, m = 0, s = 0, ms = 0, us = 0) {
|
|
57
|
+
switch (arguments.length) {
|
|
58
|
+
case 1:
|
|
59
|
+
// ticks
|
|
60
|
+
return fromTicks(arguments[0]);
|
|
61
|
+
case 3:
|
|
62
|
+
// h,m,s
|
|
63
|
+
d = 0, h = arguments[0], m = arguments[1], s = arguments[2], ms = 0;
|
|
64
|
+
break;
|
|
65
|
+
default:
|
|
66
|
+
// d,h,m,s,ms,us
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
return fromNanoseconds(unitToNanoseconds(d, nsPerDay) + unitToNanoseconds(h, nsPerHour) + unitToNanoseconds(m, nsPerMinute)
|
|
70
|
+
+ unitToNanoseconds(s, nsPerSecond) + unitToNanoseconds(ms, nsPerMillisecond) + unitToNanoseconds(us, 1000n));
|
|
71
|
+
}
|
|
72
|
+
export function fromTicks(ticks) {
|
|
73
|
+
return fromNanoseconds(BigInt(ticks) * 100n);
|
|
74
|
+
}
|
|
75
|
+
export function zero() {
|
|
76
|
+
return new Temporal.Duration();
|
|
77
|
+
}
|
|
78
|
+
const ticksPerUnit = {
|
|
79
|
+
days: 864000000000,
|
|
80
|
+
hours: 36000000000,
|
|
81
|
+
minutes: 600000000,
|
|
82
|
+
seconds: 10000000,
|
|
83
|
+
milliseconds: 10000,
|
|
84
|
+
};
|
|
85
|
+
// The DateTime/DateTimeOffset/TimeOnly Add* members take a double and are
|
|
86
|
+
// tick-precise in .NET: the value is scaled to ticks and rounded, so
|
|
87
|
+
// AddSeconds(0.0000001) moves exactly one tick and AddDays(1.5) exactly 36 hours.
|
|
88
|
+
// Temporal's own `add({ days: 1.5 })` rejects non-integers, so the scaling has to
|
|
89
|
+
// happen here.
|
|
90
|
+
export function fromUnits(value, unit) {
|
|
91
|
+
return fromTicks(BigInt(Math.round(value * ticksPerUnit[unit])));
|
|
92
|
+
}
|
|
93
|
+
export function fromDays(d, h = 0, m = 0n, s = 0n, ms = 0n) {
|
|
94
|
+
return create(d, h, Number(m), Number(s), Number(ms));
|
|
95
|
+
}
|
|
96
|
+
export function fromHours(h, m = 0n, s = 0n, ms = 0n) {
|
|
97
|
+
return create(0, h, Number(m), Number(s), Number(ms));
|
|
98
|
+
}
|
|
99
|
+
export function fromMinutes(m, s = 0n, ms = 0n) {
|
|
100
|
+
return create(0, 0, Number(m), Number(s), Number(ms));
|
|
101
|
+
}
|
|
102
|
+
export function fromSeconds(s, ms = 0n) {
|
|
103
|
+
return create(0, 0, 0, Number(s), Number(ms));
|
|
104
|
+
}
|
|
105
|
+
export function fromMilliseconds(ms) {
|
|
106
|
+
return fromNanoseconds(unitToNanoseconds(Number(ms), nsPerMillisecond));
|
|
107
|
+
}
|
|
108
|
+
export function ticks(ts) {
|
|
109
|
+
return toInt64(totalNanoseconds(ts) / 100n);
|
|
110
|
+
}
|
|
111
|
+
// .NET computes each total as (double)Ticks / TicksPerUnit; match that exactly
|
|
112
|
+
// (Temporal's own .total() balances differently and can be 1 ULP off).
|
|
113
|
+
function totalTicks(ts) {
|
|
114
|
+
return Number(totalNanoseconds(ts) / 100n);
|
|
115
|
+
}
|
|
116
|
+
export function totalDays(ts) {
|
|
117
|
+
return totalTicks(ts) / 864000000000;
|
|
118
|
+
}
|
|
119
|
+
export function totalHours(ts) {
|
|
120
|
+
return totalTicks(ts) / 36000000000;
|
|
121
|
+
}
|
|
122
|
+
export function totalMinutes(ts) {
|
|
123
|
+
return totalTicks(ts) / 600000000;
|
|
124
|
+
}
|
|
125
|
+
export function totalSeconds(ts) {
|
|
126
|
+
return totalTicks(ts) / 10000000;
|
|
127
|
+
}
|
|
128
|
+
export function totalMilliseconds(ts) {
|
|
129
|
+
return totalTicks(ts) / 10000;
|
|
130
|
+
}
|
|
131
|
+
export function negate(ts) {
|
|
132
|
+
return ts.negated();
|
|
133
|
+
}
|
|
134
|
+
export function add(ts1, ts2) {
|
|
135
|
+
return fromNanoseconds(totalNanoseconds(ts1) + totalNanoseconds(ts2));
|
|
136
|
+
}
|
|
137
|
+
export function subtract(ts1, ts2) {
|
|
138
|
+
return fromNanoseconds(totalNanoseconds(ts1) - totalNanoseconds(ts2));
|
|
139
|
+
}
|
|
140
|
+
// .NET scales the tick count as a double and rounds: `new TimeSpan((long)Math
|
|
141
|
+
// .Round(Ticks * factor))`. Scaling ticks rather than nanoseconds keeps the
|
|
142
|
+
// magnitude — and so the rounding — identical to .NET's.
|
|
143
|
+
export function multiply(ts, factor) {
|
|
144
|
+
return fromTicks(BigInt(Math.round(Number(ticks(ts)) * factor)));
|
|
145
|
+
}
|
|
146
|
+
export function divide(ts, factor) {
|
|
147
|
+
return fromTicks(BigInt(Math.round(Number(ticks(ts)) / factor)));
|
|
148
|
+
}
|
|
149
|
+
export function divideByTimeSpan(ts, other) {
|
|
150
|
+
return Number(ticks(ts)) / Number(ticks(other));
|
|
151
|
+
}
|
|
152
|
+
export const op_Addition = add;
|
|
153
|
+
export const op_Subtraction = subtract;
|
|
154
|
+
export const op_Multiply = multiply;
|
|
155
|
+
export const op_UnaryNegation = negate;
|
|
156
|
+
export function compare(x, y) {
|
|
157
|
+
return Temporal.Duration.compare(x, y);
|
|
158
|
+
}
|
|
159
|
+
export const compareTo = compare;
|
|
160
|
+
export function equals(x, y) {
|
|
161
|
+
return Temporal.Duration.compare(x, y) === 0;
|
|
162
|
+
}
|
|
163
|
+
export function hash(ts) {
|
|
164
|
+
return Number(totalNanoseconds(ts) % 2147483647n);
|
|
165
|
+
}
|
|
166
|
+
export function duration(ts) {
|
|
167
|
+
return ts.abs();
|
|
168
|
+
}
|
|
169
|
+
export function toString(ts, format = "c", _provider) {
|
|
170
|
+
if (["c", "g", "G"].indexOf(format) === -1) {
|
|
171
|
+
throw new Exception("Custom formats are not supported");
|
|
172
|
+
}
|
|
173
|
+
const d = Math.abs(ts.days);
|
|
174
|
+
const h = Math.abs(ts.hours);
|
|
175
|
+
const m = Math.abs(ts.minutes);
|
|
176
|
+
const s = Math.abs(ts.seconds);
|
|
177
|
+
const ticks = Math.abs(ts.milliseconds) * 10000
|
|
178
|
+
+ Math.abs(ts.microseconds) * 10
|
|
179
|
+
+ Math.trunc(Math.abs(ts.nanoseconds) / 100);
|
|
180
|
+
const sign = ts.sign < 0 ? "-" : "";
|
|
181
|
+
const days = d === 0 && format !== "G" ? "" : format === "c" ? d + "." : d + ":";
|
|
182
|
+
const time = `${format === "g" ? h : padWithZeros(h, 2)}:${padWithZeros(m, 2)}:${padWithZeros(s, 2)}`;
|
|
183
|
+
// .NET prints seven tick digits for "c" and "G", trims trailing zeros for "g", and omits a zero fraction for "c" and "g".
|
|
184
|
+
const fraction = format === "g"
|
|
185
|
+
? (ticks === 0 ? "" : "." + padWithZeros(ticks, 7).replace(/0+$/, ""))
|
|
186
|
+
: (ticks === 0 && format === "c" ? "" : "." + padWithZeros(ticks, 7));
|
|
187
|
+
return `${sign}${days}${time}${fraction}`;
|
|
188
|
+
}
|
|
189
|
+
export function parse(str) {
|
|
190
|
+
const firstDot = str.search("\\.");
|
|
191
|
+
const firstColon = str.search("\\:");
|
|
192
|
+
if (firstDot === -1 && firstColon === -1) { // There is only a day ex: 4
|
|
193
|
+
const d = parseInt(str, 0);
|
|
194
|
+
if (isNaN(d)) {
|
|
195
|
+
throw new Exception(`String '${str}' was not recognized as a valid TimeSpan.`);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
return create(d, 0, 0, 0, 0);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (firstColon > 0) { // process time part
|
|
202
|
+
// WIP: (-?)(((\d+)\.)?([0-9]|0[0-9]|1[0-9]|2[0-3]):(\d+)(:\d+(\.\d{1,7})?)?|\d+(?:(?!\.)))
|
|
203
|
+
const r = /^(-?)((\d+)\.)?(?:0*)([0-9]|0[0-9]|1[0-9]|2[0-3]):(?:0*)([0-5][0-9]|[0-9])(:(?:0*)([0-5][0-9]|[0-9]))?\.?(\d+)?$/.exec(str);
|
|
204
|
+
if (r != null && r[4] != null && r[5] != null) {
|
|
205
|
+
let d = 0;
|
|
206
|
+
let ms = 0;
|
|
207
|
+
let s = 0;
|
|
208
|
+
const sign = r[1] != null && r[1] === "-" ? -1 : 1;
|
|
209
|
+
const h = +r[4];
|
|
210
|
+
const m = +r[5];
|
|
211
|
+
if (r[3] != null) {
|
|
212
|
+
d = +r[3];
|
|
213
|
+
}
|
|
214
|
+
if (r[7] != null) {
|
|
215
|
+
s = +r[7];
|
|
216
|
+
}
|
|
217
|
+
if (r[8] != null) {
|
|
218
|
+
// Depending on the number of decimals passed, we need to adapt the numbers
|
|
219
|
+
switch (r[8].length) {
|
|
220
|
+
case 1:
|
|
221
|
+
ms = +r[8] * 100;
|
|
222
|
+
break;
|
|
223
|
+
case 2:
|
|
224
|
+
ms = +r[8] * 10;
|
|
225
|
+
break;
|
|
226
|
+
case 3:
|
|
227
|
+
ms = +r[8];
|
|
228
|
+
break;
|
|
229
|
+
case 4:
|
|
230
|
+
ms = +r[8] / 10;
|
|
231
|
+
break;
|
|
232
|
+
case 5:
|
|
233
|
+
ms = +r[8] / 100;
|
|
234
|
+
break;
|
|
235
|
+
case 6:
|
|
236
|
+
ms = +r[8] / 1000;
|
|
237
|
+
break;
|
|
238
|
+
case 7:
|
|
239
|
+
ms = +r[8] / 10000;
|
|
240
|
+
break;
|
|
241
|
+
default:
|
|
242
|
+
throw new Exception(`String '${str}' was not recognized as a valid TimeSpan.`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const ts = create(d, h, m, s, ms);
|
|
246
|
+
return sign < 0 ? negate(ts) : ts;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
throw new Exception(`String '${str}' was not recognized as a valid TimeSpan.`);
|
|
250
|
+
}
|
|
251
|
+
export function tryParse(v, defValue) {
|
|
252
|
+
try {
|
|
253
|
+
defValue.contents = parse(v);
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
}
|
package/lib/big.js
CHANGED
|
@@ -210,6 +210,9 @@ function round(x, sd, rm, more) {
|
|
|
210
210
|
}
|
|
211
211
|
return x;
|
|
212
212
|
}
|
|
213
|
+
function hasNonzeroDigit(x) {
|
|
214
|
+
return x.c.some(d => d !== 0);
|
|
215
|
+
}
|
|
213
216
|
/*
|
|
214
217
|
* Return a string representing the value of Big x in normal or exponential notation.
|
|
215
218
|
* Handles P.toExponential, P.toFixed, P.toJSON, P.toPrecision, P.toString and P.valueOf.
|
|
@@ -728,7 +731,7 @@ P.times = P.mul = function (y) {
|
|
|
728
731
|
* rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up).
|
|
729
732
|
*/
|
|
730
733
|
P.toExponential = function (dp, rm) {
|
|
731
|
-
var x = this, n = x
|
|
734
|
+
var x = this, n = hasNonzeroDigit(x);
|
|
732
735
|
if (dp !== UNDEFINED) {
|
|
733
736
|
if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
|
|
734
737
|
throw Error(INVALID_DP);
|
|
@@ -737,7 +740,7 @@ P.toExponential = function (dp, rm) {
|
|
|
737
740
|
for (; x.c.length < dp;)
|
|
738
741
|
x.c.push(0);
|
|
739
742
|
}
|
|
740
|
-
return stringify(x, true,
|
|
743
|
+
return stringify(x, true, n);
|
|
741
744
|
};
|
|
742
745
|
/*
|
|
743
746
|
* Return a string representing the value of this Big in normal notation rounded to dp fixed
|
|
@@ -746,21 +749,22 @@ P.toExponential = function (dp, rm) {
|
|
|
746
749
|
* dp? {number} Decimal places: integer, 0 to MAX_DP inclusive.
|
|
747
750
|
* rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up).
|
|
748
751
|
*
|
|
749
|
-
*
|
|
750
|
-
* (-0).toFixed(
|
|
752
|
+
* Unlike JavaScript, the sign is omitted when the rounded result is zero:
|
|
753
|
+
* (-0.1).toFixed(0) is '0' and (-0.01).toFixed(1) is '0.0', matching .NET.
|
|
751
754
|
*/
|
|
752
755
|
P.toFixed = function (dp, rm) {
|
|
753
|
-
var x = this
|
|
756
|
+
var x = this;
|
|
754
757
|
if (dp !== UNDEFINED) {
|
|
755
758
|
if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
|
|
756
759
|
throw Error(INVALID_DP);
|
|
757
760
|
}
|
|
758
|
-
x =
|
|
761
|
+
x = new x.constructor(x);
|
|
762
|
+
x = round(x, dp + x.e + 1, rm);
|
|
759
763
|
// x.e may have changed if the value is rounded up.
|
|
760
764
|
for (dp = dp + x.e + 1; x.c.length < dp;)
|
|
761
765
|
x.c.push(0);
|
|
762
766
|
}
|
|
763
|
-
return stringify(x, false,
|
|
767
|
+
return stringify(x, false, hasNonzeroDigit(x));
|
|
764
768
|
};
|
|
765
769
|
/*
|
|
766
770
|
* Return a string representing the value of this Big.
|
|
@@ -770,7 +774,7 @@ P.toFixed = function (dp, rm) {
|
|
|
770
774
|
*/
|
|
771
775
|
P.toJSON = P.toString = function () {
|
|
772
776
|
var x = this, Big = x.constructor;
|
|
773
|
-
return stringify(x, x.e <= Big.NE || x.e >= Big.PE,
|
|
777
|
+
return stringify(x, x.e <= Big.NE || x.e >= Big.PE, hasNonzeroDigit(x));
|
|
774
778
|
};
|
|
775
779
|
/*
|
|
776
780
|
* Return the value of this Big as a primitve number.
|
|
@@ -792,7 +796,7 @@ P.toNumber = function () {
|
|
|
792
796
|
* rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up).
|
|
793
797
|
*/
|
|
794
798
|
P.toPrecision = function (sd, rm) {
|
|
795
|
-
var x = this, Big = x.constructor, n = x
|
|
799
|
+
var x = this, Big = x.constructor, n = hasNonzeroDigit(x);
|
|
796
800
|
if (sd !== UNDEFINED) {
|
|
797
801
|
if (sd !== ~~sd || sd < 1 || sd > MAX_DP) {
|
|
798
802
|
throw Error(INVALID + 'precision');
|
|
@@ -801,7 +805,7 @@ P.toPrecision = function (sd, rm) {
|
|
|
801
805
|
for (; x.c.length < sd;)
|
|
802
806
|
x.c.push(0);
|
|
803
807
|
}
|
|
804
|
-
return stringify(x, sd <= x.e || x.e <= Big.NE || x.e >= Big.PE,
|
|
808
|
+
return stringify(x, sd <= x.e || x.e <= Big.NE || x.e >= Big.PE, n);
|
|
805
809
|
};
|
|
806
810
|
/*
|
|
807
811
|
* Return a string representing the value of this Big.
|
package/package.json
CHANGED