Skip to content

Commit 95421a5

Browse files
Improve parsing of offsets and fractional seconds
1 parent 5520274 commit 95421a5

File tree

4 files changed

+3276
-1721
lines changed

4 files changed

+3276
-1721
lines changed

std/assembly/date.ts

Lines changed: 35 additions & 9 deletions
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,25 +62,49 @@ 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+
let offsetParts = timeString.substring(i+1).split(":");
77+
let offsetHours = i32.parse(offsetParts[0]);
78+
let offsetMinutes = offsetParts.length >= 2 ? i32.parse(offsetParts[1]) : 0;
79+
offsetMs = (offsetHours * 60 + offsetMinutes) * 60000;
80+
if (c == 45) {
81+
offsetMs = -offsetMs; // negative offset
82+
}
83+
timeString = timeString.substring(0, i);
84+
break;
85+
}
86+
}
87+
88+
// parse the HH:MM:SS component
6589
let timeParts = timeString.split(":");
6690
let len = timeParts.length;
6791
if (len <= 1) throw new RangeError(E_INVALIDDATE);
6892

6993
hour = i32.parse(timeParts[0]);
7094
min = i32.parse(timeParts[1]);
7195
if (len >= 3) {
72-
let secAndMs = timeParts[2];
73-
let posDot = secAndMs.indexOf(".");
96+
let secAndFrac = timeParts[2];
97+
let posDot = secAndFrac.indexOf(".");
7498
if (~posDot) {
75-
// includes milliseconds
76-
sec = i32.parse(secAndMs.substring(0, posDot));
77-
ms = i32.parse(secAndMs.substring(posDot + 1));
99+
// includes fractional seconds (truncate to milliseconds)
100+
sec = i32.parse(secAndFrac.substring(0, posDot));
101+
ms = i32.parse(secAndFrac.substr(posDot + 1, 3).padEnd(3, "0"));
78102
} else {
79-
sec = i32.parse(secAndMs);
103+
sec = i32.parse(secAndFrac);
80104
}
81105
}
82106
}
107+
83108
// parse the YYYY-MM-DD component
84109
let parts = dateString.split("-");
85110
let year = i32.parse(parts[0]);
@@ -91,7 +116,8 @@ export class Date {
91116
day = i32.parse(parts[2]);
92117
}
93118
}
94-
return new Date(epochMillis(year, month, day, hour, min, sec, ms));
119+
120+
return new Date(epochMillis(year, month, day, hour, min, sec, ms) - offsetMs);
95121
}
96122

97123
constructor(private epochMillis: i64) {

0 commit comments

Comments
 (0)