Skip to content

Commit 9ca63f2

Browse files
authored
fix: optimize dayOfWeek & dateFromEpoch routines in date (#3033)
1 parent 2829037 commit 9ca63f2

4 files changed

Lines changed: 2247 additions & 1790 deletions

File tree

std/assembly/date.ts

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@ import { Date as Date_binding } from "./bindings/dom";
33

44
// @ts-ignore: decorator
55
@inline const
6+
MILLIS_LIMIT = 8640000000000000,
67
MILLIS_PER_DAY = 1000 * 60 * 60 * 24,
78
MILLIS_PER_HOUR = 1000 * 60 * 60,
89
MILLIS_PER_MINUTE = 1000 * 60,
910
MILLIS_PER_SECOND = 1000,
10-
11-
YEARS_PER_EPOCH = 400,
12-
DAYS_PER_EPOCH = 146097,
13-
EPOCH_OFFSET = 719468, // Jan 1, 1970
14-
MILLIS_LIMIT = 8640000000000000;
11+
YEARS_PER_EPOCH = 400,
12+
DAYS_PER_EPOCH = 146097, // 400 * 365 + 400 / 4 - 400 / 100 + 1
13+
EPOCH_OFFSET = 719468; // Jan 1, 1970
1514

1615
// ymdFromEpochDays returns values via globals to avoid allocations
1716
// @ts-ignore: decorator
@@ -62,7 +61,7 @@ export class Date {
6261
let timeString: string;
6362
dateString = dateTimeString.substring(0, posT);
6463
timeString = dateTimeString.substring(posT + 1);
65-
64+
6665
// might end with an offset ("Z", "+05:30", "-08:00", etc.)
6766
for (let i = timeString.length - 1; i >= 0; i--) {
6867
let c = timeString.charCodeAt(i);
@@ -82,8 +81,8 @@ export class Date {
8281
} else {
8382
let offsetHours = i32.parse(timeString.substring(i + 1));
8483
offsetMs = offsetHours * MILLIS_PER_HOUR;
85-
}
86-
84+
}
85+
8786
if (c == 45) offsetMs = -offsetMs; // negative offset
8887
timeString = timeString.substring(0, i);
8988
break;
@@ -333,25 +332,23 @@ function invalidDate(millis: i64): bool {
333332
// Paper: https://arxiv.org/pdf/2102.06959.pdf
334333
function dateFromEpoch(ms: i64): i32 {
335334
let da = (<i32>floorDiv(ms, MILLIS_PER_DAY) * 4 + EPOCH_OFFSET * 4) | 3;
336-
let q0 = floorDiv(da, DAYS_PER_EPOCH); // [0, 146096]
335+
let q0 = floorDiv(da, DAYS_PER_EPOCH); // [0, 146096]
337336
let r1 = <u32>da - q0 * DAYS_PER_EPOCH;
338337
let u1 = u64(r1 | 3) * 2939745;
339338
let dm1 = <u32>u1 / 11758980;
340339
let n1 = 2141 * dm1 + 197913;
341340
let year = 100 * q0 + i32(u1 >>> 32);
342-
let mo = n1 >>> 16;
343-
_day = (n1 & 0xFFFF) / 2141 + 1; // [1, 31]
344-
if (dm1 >= 306) { mo -= 12; ++year; }
345-
_month = mo; // [1, 12]
346-
return year;
341+
_day = (n1 & 0xFFFF) / 2141 + 1; // [1, 31]
342+
_month = (n1 >>> 16) - (dm1 >= 306 ? 12 : 0); // [1, 12]
343+
return year + (dm1 >= 306 ? 1 : 0);
347344
}
348345

349346
// http://howardhinnant.github.io/date_algorithms.html#days_from_civil
350-
function daysSinceEpoch(y: i32, m: i32, d: i32): i64 {
351-
y -= i32(m <= 2);
352-
let era = <u32>floorDiv(y, YEARS_PER_EPOCH);
353-
let yoe = <u32>y - era * YEARS_PER_EPOCH; // [0, 399]
354-
let doy = <u32>(153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; // [0, 365]
347+
function daysSinceEpoch(year: i32, month: i32, day: i32): i64 {
348+
year -= i32(month <= 2);
349+
let era = <u32>floorDiv(year, YEARS_PER_EPOCH);
350+
let yoe = <u32>year - era * YEARS_PER_EPOCH; // [0, 399]
351+
let doy = <u32>(153 * (month + (month > 2 ? -3 : 9)) + 2) / 5 + day - 1; // [0, 365]
355352
let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096]
356353
return <i64><i32>(era * 146097 + doe - EPOCH_OFFSET);
357354
}
@@ -360,8 +357,9 @@ function daysSinceEpoch(y: i32, m: i32, d: i32): i64 {
360357
function dayOfWeek(year: i32, month: i32, day: i32): i32 {
361358
const tab = memory.data<u8>([0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]);
362359

363-
year -= i32(month < 3);
364-
year += floorDiv(year, 4) - floorDiv(year, 100) + floorDiv(year, YEARS_PER_EPOCH);
360+
year -= i32(month <= 2);
361+
const cent = floorDiv(year >> 2, 100 >> 2);
362+
year += (year >> 2) - cent + (cent >> 2);
365363
month = <i32>load<u8>(tab + month - 1);
366364
return euclidRem(year + month + day, 7);
367365
}

0 commit comments

Comments
 (0)