Skip to content

Refactor stringify methods of Date #2398

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 63 additions & 82 deletions std/assembly/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,125 +169,98 @@ export class Date {

setUTCDate(day: i32): void {
if (this.day == day) return;
var ms = euclidRem(this.epochMillis, MILLIS_PER_DAY);
this.setTime(i64(daysSinceEpoch(this.year, this.month, day)) * MILLIS_PER_DAY + ms);
this.setTime(join(this.year, this.month, day, this.epochMillis));
}

setUTCMonth(month: i32, day: i32 = this.day): void {
if (this.month == month + 1) return;
var ms = euclidRem(this.epochMillis, MILLIS_PER_DAY);
this.setTime(i64(daysSinceEpoch(this.year, month + 1, day)) * MILLIS_PER_DAY + ms);
this.setTime(join(this.year, month + 1, day, this.epochMillis));
}

setUTCFullYear(year: i32): void {
if (this.year == year) return;
var ms = euclidRem(this.epochMillis, MILLIS_PER_DAY);
this.setTime(i64(daysSinceEpoch(year, this.month, this.day)) * MILLIS_PER_DAY + ms);
this.setTime(join(year, this.month, this.day, this.epochMillis));
}

toISOString(): string {
// TODO: add more low-level helper which combine toString and padStart without extra allocation
var yearStr: string;
var year = this.year;
var isNeg = year < 0;
if (isNeg || year >= 10000) {
yearStr = (isNeg ? "-" : "+") + abs(year).toString().padStart(6, "0");
} else {
yearStr = year.toString().padStart(4, "0");
}

return (
yearStr +
"-" +
this.month.toString().padStart(2, "0") +
"-" +
this.day.toString().padStart(2, "0") +
"T" +
this.getUTCHours().toString().padStart(2, "0") +
":" +
this.getUTCMinutes().toString().padStart(2, "0") +
":" +
this.getUTCSeconds().toString().padStart(2, "0") +
"." +
this.getUTCMilliseconds().toString().padStart(3, "0") +
"Z"
);
var yr = this.year;
var isNeg = yr < 0;
var year = (isNeg || yr >= 10000)
? (isNeg ? "-" : "+") + stringify(abs(yr), 6)
: stringify(yr, 4);
var month = stringify(this.month, 2);
var day = stringify(this.day);
var hours = stringify(this.getUTCHours());
var mins = stringify(this.getUTCMinutes());
var secs = stringify(this.getUTCSeconds());
var ms = stringify(this.getUTCMilliseconds(), 3);

return `${year}-${month}-${day}T${hours}:${mins}:${secs}.${ms}Z`;
}

toUTCString(): string {
const weeks: StaticArray<string> = [
"Sun, ", "Mon, ", "Tue, ", "Wed, ", "Thu, ", "Fri, ", "Sat, "
];

const months: StaticArray<string> = [
" Jan ", " Feb ", " Mar ", " Apr ", " May ", " Jun ",
" Jul ", " Aug ", " Sep ", " Oct ", " Nov ", " Dec "
];
const
weeks: StaticArray<string> = [
"Sun, ", "Mon, ", "Tue, ", "Wed, ", "Thu, ", "Fri, ", "Sat, "
],
months: StaticArray<string> = [
" Jan ", " Feb ", " Mar ", " Apr ", " May ", " Jun ",
" Jul ", " Aug ", " Sep ", " Oct ", " Nov ", " Dec "
];

var mo = this.month;
var da = this.day;
var yr = this.year;
var wd = dayOfWeek(yr, mo, da);
var year = abs(yr).toString().padStart(4, "0");
if (yr < 0) year = "-" + year;

return (
unchecked(weeks[wd]) +
da.toString().padStart(2, "0") +
unchecked(months[mo - 1]) +
year +
" " +
this.getUTCHours().toString().padStart(2, "0") +
":" +
this.getUTCMinutes().toString().padStart(2, "0") +
":" +
this.getUTCSeconds().toString().padStart(2, "0") +
" GMT"
);
var year = stringify(abs(yr), 4);
var month = unchecked(months[mo - 1]);
var week = unchecked(weeks[wd]);
var day = stringify(da);
var hours = stringify(this.getUTCHours());
var mins = stringify(this.getUTCMinutes());
var secs = stringify(this.getUTCSeconds());

return `${week}${day}${month}${yr < 0 ? "-" : ""}${year} ${hours}:${mins}:${secs} GMT`;
}

toDateString(): string {
// TODO: use u64 static data instead 4 chars
// also use stream itoa variants.
const weeks: StaticArray<string> = [
"Sun ", "Mon ", "Tue ", "Wed ", "Thu ", "Fri ", "Sat "
];

const months: StaticArray<string> = [
"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ",
"Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "
];
const
weeks: StaticArray<string> = [
"Sun ", "Mon ", "Tue ", "Wed ", "Thu ", "Fri ", "Sat "
],
months: StaticArray<string> = [
"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ",
"Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "
];

var mo = this.month;
var da = this.day;
var yr = this.year;
var wd = dayOfWeek(yr, mo, da);
var year = abs(yr).toString().padStart(4, "0");
if (yr < 0) year = "-" + year;

return (
unchecked(weeks[wd]) +
unchecked(months[mo - 1]) +
da.toString().padStart(2, "0") +
" " + year
);
var year = stringify(abs(yr), 4);
var month = unchecked(months[mo - 1]);
var week = unchecked(weeks[wd]);
var day = stringify(da);

return `${week}${month}${day}${yr < 0 ? " -" : " "}${year}`;
}

// Note: it uses UTC time instead local time (without timezone offset)
toTimeString(): string {
var hours = stringify(this.getUTCHours());
var mins = stringify(this.getUTCMinutes());
var secs = stringify(this.getUTCSeconds());
// TODO: add timezone
return (
this.getUTCHours().toString().padStart(2, "0") +
":" +
this.getUTCMinutes().toString().padStart(2, "0") +
":" +
this.getUTCSeconds().toString().padStart(2, "0")
);
return `${hours}:${mins}:${secs}`;
}

// Note: it uses UTC datetime instead local datetime (without timezone offset)
toString(): string {
return this.toDateString() + " " + this.toTimeString();
return `${this.toDateString()} ${this.toTimeString()}`;
}
}

Expand All @@ -301,7 +274,7 @@ function epochMillis(
milliseconds: i32
): i64 {
return (
i64(daysSinceEpoch(year, month, day)) * MILLIS_PER_DAY +
daysSinceEpoch(year, month, day) * MILLIS_PER_DAY +
hour * MILLIS_PER_HOUR +
minute * MILLIS_PER_MINUTE +
second * MILLIS_PER_SECOND +
Expand Down Expand Up @@ -343,13 +316,13 @@ function dateFromEpoch(ms: i64): i32 {
}

// http://howardhinnant.github.io/date_algorithms.html#days_from_civil
function daysSinceEpoch(y: i32, m: i32, d: i32): i32 {
function daysSinceEpoch(y: i32, m: i32, d: i32): i64 {
y -= i32(m <= 2);
var era = <u32>floorDiv(y, YEARS_PER_EPOCH);
var yoe = <u32>y - era * YEARS_PER_EPOCH; // [0, 399]
var doy = <u32>(153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; // [0, 365]
var doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096]
return era * 146097 + doe - EPOCH_OFFSET;
return <i64><i32>(era * 146097 + doe - EPOCH_OFFSET);
}

// TomohikoSakamoto algorithm from https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week
Expand All @@ -361,3 +334,11 @@ function dayOfWeek(year: i32, month: i32, day: i32): i32 {
month = <i32>load<u8>(tab + month - 1);
return euclidRem(year + month + day, 7);
}

function stringify(value: i32, padding: i32 = 2): string {
return value.toString().padStart(padding, "0");
}

function join(year: i32, month: i32, day: i32, ms: i64): i64 {
return daysSinceEpoch(year, month, day) * MILLIS_PER_DAY + euclidRem(ms, MILLIS_PER_DAY);
}
Loading