Skip to content

Commit

Permalink
fix: TimeOnly and DateOnly responses from the server not parsed corre…
Browse files Browse the repository at this point in the history
…ctly.
  • Loading branch information
ascott18 committed Sep 28, 2023
1 parent dbfd17f commit d4f372f
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/coalesce-vue/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export function parseValue(
if (value instanceof Date) {
date = value;
} else if (type === "string") {
date = parseJSONDate(value);
date = parseJSONDate(value, meta.dateKind);
}

// isNaN is what date-fn's `isValid` calls internally,
Expand Down
40 changes: 36 additions & 4 deletions src/coalesce-vue/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ export function isNullOrWhitespace(value: string | null | undefined) {
}

const iso8601DateRegex =
/^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2}):(\d{2})(?:\.(\d{0,7}))?(?:Z|(.)(\d{2}):?(\d{2})?)?/;
export function parseJSONDate(argument: string) {
/^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2}):(\d{2})(?:\.(\d{0,7}))?(?:Z|(.)(\d{2}):?(\d{2})?)?)?/;
const iso8601TimeRegex =
/^(\d{2}):(\d{2}):(\d{2})(?:\.(\d{0,7}))?(?:Z|(.)(\d{2}):?(\d{2})?)?$/;
export function parseJSONDate(argument: string, kind: DateKind = "datetime") {
// DO NOT USE `new Date()` here.
// Safari incorrectly interprets times without a timezone offset
// (i.e. DateTime objects in c#) as UTC instead of local time.
Expand All @@ -61,10 +63,36 @@ export function parseJSONDate(argument: string) {
// This method is only slightly slower than parseJSON,
// but is still 3-4x faster than parseISO while also having much, much less code.

if (kind == "time") {
// Time-only formats might come from the server as truly only a time (C# TimeOnly type).
// "ISO 8601: Time without UTC offset information" https://github.com/dotnet/runtime/issues/53539

var timeParts = argument.match(iso8601TimeRegex) || [];
if (timeParts.length >= 3) {
// If ES Temporal was standardize we could maybe switch Coalesce to use it,
// but for now we just settle for using a Date and ignoring the time part.

// NOTE: We set the date to Jan 1 in to avoid Daylight Savings switch days,
// which if such a date were to be the date component of the `Date`, would fail
// to represent the time correctly.
return new Date(
new Date().getFullYear(),
0,
1,
+timeParts[1], // h
+timeParts[2], // m
+timeParts[3], // s
+((timeParts[4] || "0") + "00").substring(0, 3) // ms (maybe never used?)
);
}
}

var parts = argument.match(iso8601DateRegex) || [];

const part9 = parts[9];
const part9 = parts[9]; // TZ offset

if (part9 !== undefined) {
// Date+Time, with offset specifier
return new Date(
Date.UTC(
+parts[1],
Expand All @@ -76,7 +104,8 @@ export function parseJSONDate(argument: string) {
+((parts[7] || "0") + "00").substring(0, 3)
)
);
} else {
} else if (parts[4] !== undefined) {
// Date+Time, without offset specifier
return new Date(
+parts[1],
+parts[2] - 1,
Expand All @@ -86,6 +115,9 @@ export function parseJSONDate(argument: string) {
+parts[6],
+((parts[7] || "0") + "00").substring(0, 3)
);
} else {
// Date only, without a time portion:
return new Date(+parts[1], +parts[2] - 1, +parts[3]);
}
}

Expand Down
17 changes: 17 additions & 0 deletions src/coalesce-vue/test/model.toModel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,23 @@ const dtoToModelMappings = <MappingData[]>[
dto: "2020-06-10T14:00:00",
model: new Date(2020, 5, 10, 14, 0, 0, 0),
},
{
meta: { ...studentProps.birthDate, dateKind: "date" },
dto: "2020-06-10",
model: new Date(2020, 5, 10, 0, 0, 0, 0),
},
{
meta: { ...studentProps.birthDate, dateKind: "time" },
dto: "12:34:56",
// Time-only parses as Jan 1 of current year to avoid un-representable times on DST changeover days.
model: new Date(new Date().getFullYear(), 0, 1, 12, 34, 56, 0),
},
{
// Time-only, represented in a datetime format.
meta: { ...studentProps.birthDate, dateKind: "time" },
dto: "2020-06-10T12:34:56",
model: new Date(2020, 5, 10, 12, 34, 56, 0),
},
...unparsable(
studentProps.birthDate,
"abc",
Expand Down

0 comments on commit d4f372f

Please sign in to comment.