Skip to content

Commit

Permalink
allow unqualified date times
Browse files Browse the repository at this point in the history
  • Loading branch information
0xturner committed Oct 27, 2023
1 parent 481c9ba commit 2486484
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 8 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ z.string().uuid({ message: "Invalid UUID" });
z.string().includes("tuna", { message: "Must include tuna" });
z.string().startsWith("https://", { message: "Must provide secure URL" });
z.string().endsWith(".com", { message: "Only .com domains allowed" });
z.string().datetime({ message: "Invalid datetime string! Must be UTC." });
z.string().datetime({ message: "Invalid datetime string!" });
z.string().ip({ message: "Invalid IP address" });
```

Expand All @@ -754,6 +754,7 @@ The `z.string().datetime()` method enforces ISO 8601; default is no timezone off
const datetime = z.string().datetime();

datetime.parse("2020-01-01T00:00:00Z"); // pass
datetime.parse("2020-01-01T00:00:00"); // pass (unqualified)
datetime.parse("2020-01-01T00:00:00.123Z"); // pass
datetime.parse("2020-01-01T00:00:00.123456Z"); // pass (arbitrary precision)
datetime.parse("2020-01-01T00:00:00+02:00"); // fail (no offsets allowed)
Expand All @@ -777,6 +778,7 @@ You can additionally constrain the allowable `precision`. By default, arbitrary
const datetime = z.string().datetime({ precision: 3 });

datetime.parse("2020-01-01T00:00:00.123Z"); // pass
datetime.parse("2020-01-01T00:00:00.123"); // pass (unqualified still supported)
datetime.parse("2020-01-01T00:00:00Z"); // fail
datetime.parse("2020-01-01T00:00:00.123456Z"); // fail
```
Expand Down
4 changes: 3 additions & 1 deletion deno/lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ z.string().uuid({ message: "Invalid UUID" });
z.string().includes("tuna", { message: "Must include tuna" });
z.string().startsWith("https://", { message: "Must provide secure URL" });
z.string().endsWith(".com", { message: "Only .com domains allowed" });
z.string().datetime({ message: "Invalid datetime string! Must be UTC." });
z.string().datetime({ message: "Invalid datetime string!" });
z.string().ip({ message: "Invalid IP address" });
```

Expand All @@ -754,6 +754,7 @@ The `z.string().datetime()` method enforces ISO 8601; default is no timezone off
const datetime = z.string().datetime();

datetime.parse("2020-01-01T00:00:00Z"); // pass
datetime.parse("2020-01-01T00:00:00"); // pass (unqualified)
datetime.parse("2020-01-01T00:00:00.123Z"); // pass
datetime.parse("2020-01-01T00:00:00.123456Z"); // pass (arbitrary precision)
datetime.parse("2020-01-01T00:00:00+02:00"); // fail (no offsets allowed)
Expand All @@ -777,6 +778,7 @@ You can additionally constrain the allowable `precision`. By default, arbitrary
const datetime = z.string().datetime({ precision: 3 });

datetime.parse("2020-01-01T00:00:00.123Z"); // pass
datetime.parse("2020-01-01T00:00:00.123"); // pass (unqualified still supported)
datetime.parse("2020-01-01T00:00:00Z"); // fail
datetime.parse("2020-01-01T00:00:00.123456Z"); // fail
```
Expand Down
9 changes: 9 additions & 0 deletions deno/lib/__tests__/string.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,10 +404,15 @@ test("datetime", () => {
test("datetime parsing", () => {
const datetime = z.string().datetime();
datetime.parse("1970-01-01T00:00:00.000Z");
datetime.parse("1970-01-01T00:00:00.000");
datetime.parse("2022-10-13T09:52:31.816Z");
datetime.parse("2022-10-13T09:52:31.816");
datetime.parse("2022-10-13T09:52:31.8162314Z");
datetime.parse("2022-10-13T09:52:31.8162314");
datetime.parse("1970-01-01T00:00:00Z");
datetime.parse("1970-01-01T00:00:00");
datetime.parse("2022-10-13T09:52:31Z");
datetime.parse("2022-10-13T09:52:31");
expect(() => datetime.parse("")).toThrow();
expect(() => datetime.parse("foo")).toThrow();
expect(() => datetime.parse("2020-10-14")).toThrow();
Expand All @@ -416,15 +421,19 @@ test("datetime parsing", () => {

const datetimeNoMs = z.string().datetime({ precision: 0 });
datetimeNoMs.parse("1970-01-01T00:00:00Z");
datetimeNoMs.parse("1970-01-01T00:00:00");
datetimeNoMs.parse("2022-10-13T09:52:31Z");
datetimeNoMs.parse("2022-10-13T09:52:31");
expect(() => datetimeNoMs.parse("tuna")).toThrow();
expect(() => datetimeNoMs.parse("1970-01-01T00:00:00.000Z")).toThrow();
expect(() => datetimeNoMs.parse("1970-01-01T00:00:00.Z")).toThrow();
expect(() => datetimeNoMs.parse("2022-10-13T09:52:31.816Z")).toThrow();

const datetime3Ms = z.string().datetime({ precision: 3 });
datetime3Ms.parse("1970-01-01T00:00:00.000Z");
datetime3Ms.parse("1970-01-01T00:00:00.000");
datetime3Ms.parse("2022-10-13T09:52:31.123Z");
datetime3Ms.parse("2022-10-13T09:52:31.123");
expect(() => datetime3Ms.parse("tuna")).toThrow();
expect(() => datetime3Ms.parse("1970-01-01T00:00:00.1Z")).toThrow();
expect(() => datetime3Ms.parse("1970-01-01T00:00:00.12Z")).toThrow();
Expand Down
6 changes: 3 additions & 3 deletions deno/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ const datetimeRegex = (args: { precision: number | null; offset: boolean }) => {
);
} else {
return new RegExp(
`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{${args.precision}}Z$`
`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{${args.precision}}Z?$`
);
}
} else if (args.precision === 0) {
Expand All @@ -597,7 +597,7 @@ const datetimeRegex = (args: { precision: number | null; offset: boolean }) => {
`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(([+-]\\d{2}(:?\\d{2})?)|Z)$`
);
} else {
return new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$`);
return new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z?$`);
}
} else {
if (args.offset) {
Expand All @@ -606,7 +606,7 @@ const datetimeRegex = (args: { precision: number | null; offset: boolean }) => {
);
} else {
return new RegExp(
`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?Z$`
`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?Z?$`
);
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/__tests__/string.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,15 @@ test("datetime", () => {
test("datetime parsing", () => {
const datetime = z.string().datetime();
datetime.parse("1970-01-01T00:00:00.000Z");
datetime.parse("1970-01-01T00:00:00.000");
datetime.parse("2022-10-13T09:52:31.816Z");
datetime.parse("2022-10-13T09:52:31.816");
datetime.parse("2022-10-13T09:52:31.8162314Z");
datetime.parse("2022-10-13T09:52:31.8162314");
datetime.parse("1970-01-01T00:00:00Z");
datetime.parse("1970-01-01T00:00:00");
datetime.parse("2022-10-13T09:52:31Z");
datetime.parse("2022-10-13T09:52:31");
expect(() => datetime.parse("")).toThrow();
expect(() => datetime.parse("foo")).toThrow();
expect(() => datetime.parse("2020-10-14")).toThrow();
Expand All @@ -415,15 +420,19 @@ test("datetime parsing", () => {

const datetimeNoMs = z.string().datetime({ precision: 0 });
datetimeNoMs.parse("1970-01-01T00:00:00Z");
datetimeNoMs.parse("1970-01-01T00:00:00");
datetimeNoMs.parse("2022-10-13T09:52:31Z");
datetimeNoMs.parse("2022-10-13T09:52:31");
expect(() => datetimeNoMs.parse("tuna")).toThrow();
expect(() => datetimeNoMs.parse("1970-01-01T00:00:00.000Z")).toThrow();
expect(() => datetimeNoMs.parse("1970-01-01T00:00:00.Z")).toThrow();
expect(() => datetimeNoMs.parse("2022-10-13T09:52:31.816Z")).toThrow();

const datetime3Ms = z.string().datetime({ precision: 3 });
datetime3Ms.parse("1970-01-01T00:00:00.000Z");
datetime3Ms.parse("1970-01-01T00:00:00.000");
datetime3Ms.parse("2022-10-13T09:52:31.123Z");
datetime3Ms.parse("2022-10-13T09:52:31.123");
expect(() => datetime3Ms.parse("tuna")).toThrow();
expect(() => datetime3Ms.parse("1970-01-01T00:00:00.1Z")).toThrow();
expect(() => datetime3Ms.parse("1970-01-01T00:00:00.12Z")).toThrow();
Expand Down
6 changes: 3 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ const datetimeRegex = (args: { precision: number | null; offset: boolean }) => {
);
} else {
return new RegExp(
`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{${args.precision}}Z$`
`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{${args.precision}}Z?$`
);
}
} else if (args.precision === 0) {
Expand All @@ -597,7 +597,7 @@ const datetimeRegex = (args: { precision: number | null; offset: boolean }) => {
`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(([+-]\\d{2}(:?\\d{2})?)|Z)$`
);
} else {
return new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$`);
return new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z?$`);
}
} else {
if (args.offset) {
Expand All @@ -606,7 +606,7 @@ const datetimeRegex = (args: { precision: number | null; offset: boolean }) => {
);
} else {
return new RegExp(
`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?Z$`
`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?Z?$`
);
}
}
Expand Down

0 comments on commit 2486484

Please sign in to comment.