Skip to content

Commit

Permalink
fix: Improve date parsing (fractional seconds, UTC offsets) (#2803)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattjohnsonpint committed Nov 20, 2023
1 parent 5dec4a3 commit d142ac8
Show file tree
Hide file tree
Showing 5 changed files with 5,128 additions and 3,534 deletions.
1 change: 1 addition & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ under the licensing terms detailed in LICENSE:
* Abdul Rauf <abdulraufmujahid@gmail.com>
* Bach Le <bach@bullno1.com>
* Xinquan Xu <xinquan0203@163.com>
* Matt Johnson-Pint <mattjohnsonpint@gmail.com>

Portions of this software are derived from third-party works licensed under
the following terms:
Expand Down
59 changes: 45 additions & 14 deletions std/assembly/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ export class Date {
hour: i32 = 0,
min: i32 = 0,
sec: i32 = 0,
ms: i32 = 0;
ms: i32 = 0,
offsetMs: i32 = 0;

let dateString = dateTimeString;
let posT = dateTimeString.indexOf("T");
Expand All @@ -61,37 +62,67 @@ export class Date {
let timeString: string;
dateString = dateTimeString.substring(0, posT);
timeString = dateTimeString.substring(posT + 1);
// parse the HH-MM-SS component

// might end with an offset ("Z", "+05:30", "-08:00", etc.)
for (let i = timeString.length - 1; i >= 0; i--) {
let c = timeString.charCodeAt(i);
if (c == 90) { // Z
timeString = timeString.substring(0, i);
break;
} else if (c == 43 || c == 45) { // + or -
if (i == timeString.length - 1) {
throw new RangeError(E_INVALIDDATE);
}

let posColon = timeString.indexOf(":", i + 1);
if (~posColon) {
let offsetHours = i32.parse(timeString.substring(i + 1, posColon));
let offsetMinutes = i32.parse(timeString.substring(posColon + 1));
offsetMs = (offsetHours * 60 + offsetMinutes) * MILLIS_PER_MINUTE;
} else {
let offsetHours = i32.parse(timeString.substring(i + 1));
offsetMs = offsetHours * MILLIS_PER_HOUR;
}

if (c == 45) offsetMs = -offsetMs; // negative offset
timeString = timeString.substring(0, i);
break;
}
}

// parse the HH:MM:SS component
let timeParts = timeString.split(":");
let len = timeParts.length;
if (len <= 1) throw new RangeError(E_INVALIDDATE);

hour = I32.parseInt(timeParts[0]);
min = I32.parseInt(timeParts[1]);
hour = i32.parse(timeParts[0]);
min = i32.parse(timeParts[1]);
if (len >= 3) {
let secAndMs = timeParts[2];
let posDot = secAndMs.indexOf(".");
let secAndFrac = timeParts[2];
let posDot = secAndFrac.indexOf(".");
if (~posDot) {
// includes milliseconds
sec = I32.parseInt(secAndMs.substring(0, posDot));
ms = I32.parseInt(secAndMs.substring(posDot + 1));
// includes fractional seconds (truncate to milliseconds)
sec = i32.parse(secAndFrac.substring(0, posDot));
ms = i32.parse(secAndFrac.substr(posDot + 1, 3).padEnd(3, "0"));
} else {
sec = I32.parseInt(secAndMs);
sec = i32.parse(secAndFrac);
}
}
}

// parse the YYYY-MM-DD component
let parts = dateString.split("-");
let year = I32.parseInt(parts[0]);
let year = i32.parse(parts[0]);
let month = 1, day = 1;
let len = parts.length;
if (len >= 2) {
month = I32.parseInt(parts[1]);
month = i32.parse(parts[1]);
if (len >= 3) {
day = I32.parseInt(parts[2]);
day = i32.parse(parts[2]);
}
}
return new Date(epochMillis(year, month, day, hour, min, sec, ms));

return new Date(epochMillis(year, month, day, hour, min, sec, ms) - offsetMs);
}

constructor(private epochMillis: i64) {
Expand Down

0 comments on commit d142ac8

Please sign in to comment.