Skip to content

Commit d142ac8

Browse files
fix: Improve date parsing (fractional seconds, UTC offsets) (AssemblyScript#2803)
1 parent 5dec4a3 commit d142ac8

File tree

5 files changed

+5128
-3534
lines changed

5 files changed

+5128
-3534
lines changed

Diff for: NOTICE

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ under the licensing terms detailed in LICENSE:
5656
* Abdul Rauf <[email protected]>
5757
* Bach Le <[email protected]>
5858
* Xinquan Xu <[email protected]>
59+
* Matt Johnson-Pint <[email protected]>
5960

6061
Portions of this software are derived from third-party works licensed under
6162
the following terms:

Diff for: std/assembly/date.ts

+45-14
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ export class Date {
5252
hour: i32 = 0,
5353
min: i32 = 0,
5454
sec: i32 = 0,
55-
ms: i32 = 0;
55+
ms: i32 = 0,
56+
offsetMs: i32 = 0;
5657

5758
let dateString = dateTimeString;
5859
let posT = dateTimeString.indexOf("T");
@@ -61,37 +62,67 @@ export class Date {
6162
let timeString: string;
6263
dateString = dateTimeString.substring(0, posT);
6364
timeString = dateTimeString.substring(posT + 1);
64-
// parse the HH-MM-SS component
65+
66+
// might end with an offset ("Z", "+05:30", "-08:00", etc.)
67+
for (let i = timeString.length - 1; i >= 0; i--) {
68+
let c = timeString.charCodeAt(i);
69+
if (c == 90) { // Z
70+
timeString = timeString.substring(0, i);
71+
break;
72+
} else if (c == 43 || c == 45) { // + or -
73+
if (i == timeString.length - 1) {
74+
throw new RangeError(E_INVALIDDATE);
75+
}
76+
77+
let posColon = timeString.indexOf(":", i + 1);
78+
if (~posColon) {
79+
let offsetHours = i32.parse(timeString.substring(i + 1, posColon));
80+
let offsetMinutes = i32.parse(timeString.substring(posColon + 1));
81+
offsetMs = (offsetHours * 60 + offsetMinutes) * MILLIS_PER_MINUTE;
82+
} else {
83+
let offsetHours = i32.parse(timeString.substring(i + 1));
84+
offsetMs = offsetHours * MILLIS_PER_HOUR;
85+
}
86+
87+
if (c == 45) offsetMs = -offsetMs; // negative offset
88+
timeString = timeString.substring(0, i);
89+
break;
90+
}
91+
}
92+
93+
// parse the HH:MM:SS component
6594
let timeParts = timeString.split(":");
6695
let len = timeParts.length;
6796
if (len <= 1) throw new RangeError(E_INVALIDDATE);
6897

69-
hour = I32.parseInt(timeParts[0]);
70-
min = I32.parseInt(timeParts[1]);
98+
hour = i32.parse(timeParts[0]);
99+
min = i32.parse(timeParts[1]);
71100
if (len >= 3) {
72-
let secAndMs = timeParts[2];
73-
let posDot = secAndMs.indexOf(".");
101+
let secAndFrac = timeParts[2];
102+
let posDot = secAndFrac.indexOf(".");
74103
if (~posDot) {
75-
// includes milliseconds
76-
sec = I32.parseInt(secAndMs.substring(0, posDot));
77-
ms = I32.parseInt(secAndMs.substring(posDot + 1));
104+
// includes fractional seconds (truncate to milliseconds)
105+
sec = i32.parse(secAndFrac.substring(0, posDot));
106+
ms = i32.parse(secAndFrac.substr(posDot + 1, 3).padEnd(3, "0"));
78107
} else {
79-
sec = I32.parseInt(secAndMs);
108+
sec = i32.parse(secAndFrac);
80109
}
81110
}
82111
}
112+
83113
// parse the YYYY-MM-DD component
84114
let parts = dateString.split("-");
85-
let year = I32.parseInt(parts[0]);
115+
let year = i32.parse(parts[0]);
86116
let month = 1, day = 1;
87117
let len = parts.length;
88118
if (len >= 2) {
89-
month = I32.parseInt(parts[1]);
119+
month = i32.parse(parts[1]);
90120
if (len >= 3) {
91-
day = I32.parseInt(parts[2]);
121+
day = i32.parse(parts[2]);
92122
}
93123
}
94-
return new Date(epochMillis(year, month, day, hour, min, sec, ms));
124+
125+
return new Date(epochMillis(year, month, day, hour, min, sec, ms) - offsetMs);
95126
}
96127

97128
constructor(private epochMillis: i64) {

0 commit comments

Comments
 (0)