Repository: colinhacks/zod
Pull request #4680 (2025-06-11 23:38:08)

Improve ISO second handling

colinhacks: @copilot review

Patch:
diff --git a/package.json b/package.json
index 1b5ca25b..534f651e 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
     "lint-staged": "^12.5.0",
     "mitata": "^0.1.14",
     "prettier": "^3.5.3",
+    "recheck": "^4.5.0",
     "semver": "^7.7.2",
     "supershy": "^1.0.0",
     "tinybench": "^2.9.0",
diff --git a/packages/docs/content/api.mdx b/packages/docs/content/api.mdx
index 47e792c3..e3fb8563 100644
--- a/packages/docs/content/api.mdx
+++ b/packages/docs/content/api.mdx
@@ -355,10 +355,11 @@ The `z.iso.datetime()` method enforces ISO 8601; by default, no timezone offsets
 ```ts
 const datetime = z.iso.datetime();
 
-datetime.parse("2020-01-01T00:00:00Z"); // ✅
-datetime.parse("2020-01-01T00:00:00.123Z"); // ✅
-datetime.parse("2020-01-01T00:00:00.123456Z"); // ✅ (arbitrary precision)
-datetime.parse("2020-01-01T00:00:00+02:00"); // ❌ (no offsets allowed)
+datetime.parse("2020-01-01T06:15:00Z"); // ✅
+datetime.parse("2020-01-01T06:15:00.123Z"); // ✅
+datetime.parse("2020-01-01T06:15:00.123456Z"); // ✅ (arbitrary precision)
+datetime.parse("2020-01-01T06:15:00+02:00"); // ❌ (offsets not allowed)
+datetime.parse("2020-01-01T06:15:00"); // ❌ (local not allowed)
 ```
 
 To allow timezone offsets:
@@ -366,30 +367,47 @@ To allow timezone offsets:
 ```ts
 const datetime = z.iso.datetime({ offset: true });
 
-// result is normalized to RFC 3339 format
-datetime.parse("2020-01-01T00:00:00+02");    // ✅ "2020-01-01T00:00:00+02:00"
-datetime.parse("2020-01-01T00:00:00+0200");  // ✅ "2020-01-01T00:00:00+02:00"
-datetime.parse("2020-01-01T00:00:00+02:00"); // ✅ "2020-01-01T00:00:00+02:00"
+// allows timezone offsets
+datetime.parse("2020-01-01T06:15:00+02:00"); // ✅
+
+// basic offsets not allowed
+datetime.parse("2020-01-01T06:15:00+02");    // ❌
+datetime.parse("2020-01-01T06:15:00+0200");  // ❌
 
 // Z is still supported
-datetime.parse("2020-01-01T00:00:00Z"); // ✅ 
+datetime.parse("2020-01-01T06:15:00Z"); // ✅ 
 ```
 
 To allow unqualified (timezone-less) datetimes:
 
 ```ts
 const schema = z.iso.datetime({ local: true });
-schema.parse("2020-01-01T00:00:00"); // ✅
+schema.parse("2020-01-01T06:15:01"); // ✅
+schema.parse("2020-01-01T06:15"); // ✅ seconds optional
 ```
 
-To constrain the allowable `precision` (by default, arbitrary sub-second precision is supported).
+To constrain the allowable time `precision`. By default, seconds are optional and arbitrary sub-second precision is allowed.
 
 ```ts
-const datetime = z.iso.datetime({ precision: 3 });
+const a = z.iso.datetime();
+a.parse("2020-01-01T06:15Z"); // ✅
+a.parse("2020-01-01T06:15:00Z"); // ✅
+a.parse("2020-01-01T06:15:00.123Z"); // ✅
+
+const b = z.iso.datetime({ precision: -1 }); // minute precision (no seconds)
+b.parse("2020-01-01T06:15Z"); // ✅
+b.parse("2020-01-01T06:15:00Z"); // ❌
+b.parse("2020-01-01T06:15:00.123Z"); // ❌
 
-datetime.parse("2020-01-01T00:00:00.123Z"); // ✅
-datetime.parse("2020-01-01T00:00:00Z"); // ❌
-datetime.parse("2020-01-01T00:00:00.123456Z"); // ❌
+const c = z.iso.datetime({ precision: 0 }); // second precision only
+c.parse("2020-01-01T06:15Z"); // ❌
+c.parse("2020-01-01T06:15:00Z"); // ✅
+c.parse("2020-01-01T06:15:00.123Z"); // ❌
+
+const d = z.iso.datetime({ precision: 3 }); // millisecond precision only
+d.parse("2020-01-01T06:15Z"); // ❌
+d.parse("2020-01-01T06:15:00Z"); // ❌
+d.parse("2020-01-01T06:15:00.123Z"); // ✅
 ```
 
 ### ISO dates
@@ -406,29 +424,31 @@ date.parse("2020-01-32"); // ❌
 
 ### ISO times
 
-> Added in Zod 3.23
-
-The `z.iso.time()` method validates strings in the format `HH:MM:SS[.s+]`. The second can include arbitrary decimal precision. It does not allow timezone offsets of any kind.
+The `z.iso.time()` method validates strings in the format `HH:MM[:SS[.s+]]`. By default seconds are optional, as are sub-second deciams.
 
 ```ts
 const time = z.iso.time();
 
-time.parse("00:00:00"); // ✅
-time.parse("09:52:31"); // ✅
-time.parse("23:59:59.9999999"); // ✅ (arbitrary precision)
-
-time.parse("00:00:00.123Z"); // ❌ (no `Z` allowed)
-time.parse("00:00:00.123+02:00"); // ❌ (no offsets allowed)
+time.parse("03:15"); // ✅
+time.parse("03:15:00"); // ✅
+time.parse("03:15:00.9999999"); // ✅ (arbitrary precision)
 ```
 
-You can set the `precision` option to constrain the allowable decimal precision.
+No offsets of any kind are allowed.
 
 ```ts
-const time = z.iso.time({ precision: 3 });
+time.parse("03:15:00Z"); // ❌ (no `Z` allowed)
+time.parse("03:15:00+02:00"); // ❌ (no offsets allowed)
+```
 
-time.parse("00:00:00.123"); // ✅
-time.parse("00:00:00.123456"); // ❌
-time.parse("00:00:00"); // ❌
+Use the `precision` parameter to constrain the allowable decimal precision.
+
+```ts
+z.iso.time({ precision: -1 }); // HH:MM (minute precision)
+z.iso.time({ precision: 0 }); // HH:MM:SS (second precision)
+z.iso.time({ precision: 1 }); // HH:MM:SS.s (decisecond precision)
+z.iso.time({ precision: 2 }); // HH:MM:SS.ss (centisecond precision)
+z.iso.time({ precision: 3 }); // HH:MM:SS.sss (millisecond precision)
 ```
 
 ### IP addresses
@@ -597,7 +617,7 @@ Use `z.date()` to validate `Date` instances.
 
 ```ts
 z.date().safeParse(new Date()); // success: true
-z.date().safeParse("2022-01-12T00:00:00.000Z"); // success: false
+z.date().safeParse("2022-01-12T06:15:00.000Z"); // success: false
 ```
 
 To customize the error message:
@@ -1586,7 +1606,7 @@ const Person = z.record(Keys, z.string());
   const myRecord: MyRecord = { a: "foo" }; // ❌ missing required key `b`
   ```
 
-  In Zod 3, exhaustiveness was not checked. To replicate the Zod 3 behavior, use `z.partialRecord()`.
+  In Zod 3, exhaustiveness was not checked. To replicate the old behavior, use `z.partialRecord()`.
 
 </Callout>
 
diff --git a/packages/zod/src/v4/classic/external.ts b/packages/zod/src/v4/classic/external.ts
index eccc4704..42aba145 100644
--- a/packages/zod/src/v4/classic/external.ts
+++ b/packages/zod/src/v4/classic/external.ts
@@ -27,6 +27,7 @@ export {
   formatError,
   flattenError,
   toJSONSchema,
+  TimePrecision,
 } from "zod/v4/core";
 
 export * as locales from "../locales/index.js";
diff --git a/packages/zod/src/v4/core/api.ts b/packages/zod/src/v4/core/api.ts
index ab6efb75..582b0577 100644
--- a/packages/zod/src/v4/core/api.ts
+++ b/packages/zod/src/v4/core/api.ts
@@ -450,6 +450,13 @@ export function _jwt<T extends schemas.$ZodJWT>(
   });
 }
 
+export const TimePrecision = {
+  Any: null,
+  Minute: -1,
+  Second: 0,
+  Millisecond: 3,
+  Microsecond: 6,
+} as const;
 // ISODateTime
 export type $ZodISODateTimeParams = StringFormatParams<schemas.$ZodISODateTime, "pattern">;
 export type $ZodCheckISODateTimeParams = CheckStringFormatParams<schemas.$ZodISODateTime, "pattern">;
diff --git a/packages/zod/src/v4/core/regexes.ts b/packages/zod/src/v4/core/regexes.ts
index 9cc1d488..bfcb6a0e 100644
--- a/packages/zod/src/v4/core/regexes.ts
+++ b/packages/zod/src/v4/core/regexes.ts
@@ -77,22 +77,25 @@ export const domain: RegExp = /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.
 // https://blog.stevenlevithan.com/archives/validate-phone-number#r4-3 (regex sans spaces)
 export const e164: RegExp = /^\+(?:[0-9]){6,14}[0-9]$/;
 
-const dateSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
+// const dateSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
+const dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`;
 export const date: RegExp = /*@__PURE__*/ new RegExp(`^${dateSource}$`);
 
-function timeSource(args: { precision?: number | null }) {
-  // let regex = `\\d{2}:\\d{2}:\\d{2}`;
-  let regex = `([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d`;
-
-  if (args.precision) {
-    regex = `${regex}\\.\\d{${args.precision}}`;
-  } else if (args.precision == null) {
-    regex = `${regex}(\\.\\d+)?`;
-  }
+function timeSource(args: { precision?: number | null | undefined }) {
+  const hhmm = `(?:[01]\\d|2[0-3]):[0-5]\\d`;
+  const regex =
+    typeof args.precision === "number"
+      ? args.precision === -1
+        ? `${hhmm}`
+        : args.precision === 0
+          ? `${hhmm}:[0-5]\\d`
+          : `${hhmm}:[0-5]\\d\\.\\d{${args.precision}}`
+      : `${hhmm}(?::[0-5]\\d(?:\\.\\d+)?)?`;
   return regex;
 }
 export function time(args: {
   precision?: number | null;
+  // local?: boolean;
 }): RegExp {
   return new RegExp(`^${timeSource(args)}$`);
 }
@@ -103,15 +106,13 @@ export function datetime(args: {
   offset?: boolean;
   local?: boolean;
 }): RegExp {
-  let regex = `${dateSource}T${timeSource(args)}`;
-
-  const opts: string[] = [];
-  opts.push(args.local ? `Z?` : `Z`);
-  // if (args.offset) opts.push(`([+-]\\d{2}:?\\d{2})`);
-  // minutes, colon optional
-  if (args.offset) opts.push(`([+-]\\d{2}(?::?\\d{2})?)`);
-  regex = `${regex}(${opts.join("|")})`;
-  return new RegExp(`^${regex}$`);
+  const time = timeSource({ precision: args.precision });
+  const opts = ["Z"];
+  if (args.local) opts.push("");
+  if (args.offset) opts.push(`([+-]\\d{2}:\\d{2})`);
+  const timeRegex = `${time}(?:${opts.join("|")})`;
+
+  return new RegExp(`^${dateSource}T(?:${timeRegex})$`);
 }
 
 export const string = (params?: { minimum?: number | undefined; maximum?: number | undefined }): RegExp => {
diff --git a/packages/zod/src/v4/core/schemas.ts b/packages/zod/src/v4/core/schemas.ts
index e2ace79e..ed5c9790 100644
--- a/packages/zod/src/v4/core/schemas.ts
+++ b/packages/zod/src/v4/core/schemas.ts
@@ -606,18 +606,6 @@ export const $ZodISODateTime: core.$constructor<$ZodISODateTime> = /*@__PURE__*/
     $ZodStringFormat.init(inst, def);
 
     const _super = inst._zod.check;
-    inst._zod.check = (payload) => {
-      _super(payload);
-
-      // normalize timezone offset
-      // add colon & minutes if missing
-      // if no offset, return early
-      const curr = payload.value;
-      if (/[+-]\d\d$/.test(curr)) payload.value = curr + ":00";
-      else if (/[+-]\d\d\d\d$/.test(curr)) {
-        payload.value = curr.slice(0, -2) + ":" + curr.slice(-2);
-      }
-    };
   }
 );
 
@@ -642,8 +630,6 @@ export const $ZodISODate: core.$constructor<$ZodISODate> = /*@__PURE__*/ core.$c
 
 export interface $ZodISOTimeDef extends $ZodStringFormatDef<"time"> {
   precision?: number | null;
-  // offset?: boolean;
-  // local?: boolean;
 }
 
 export interface $ZodISOTimeInternals extends $ZodStringFormatInternals<"time"> {
@@ -659,6 +645,8 @@ export const $ZodISOTime: core.$constructor<$ZodISOTime> = /*@__PURE__*/ core.$c
   (inst, def): void => {
     def.pattern ??= regexes.time(def);
     $ZodStringFormat.init(inst, def);
+
+    const _super = inst._zod.check;
   }
 );
 
diff --git a/packages/zod/src/v4/mini/external.ts b/packages/zod/src/v4/mini/external.ts
index 4b23cf4f..da0f4105 100644
--- a/packages/zod/src/v4/mini/external.ts
+++ b/packages/zod/src/v4/mini/external.ts
@@ -19,6 +19,7 @@ export {
   formatError,
   flattenError,
   toJSONSchema,
+  TimePrecision,
 } from "zod/v4/core";
 
 export * as locales from "../locales/index.js";
diff --git a/play.ts b/play.ts
index 0a9320ce..bc79699c 100644
--- a/play.ts
+++ b/play.ts
@@ -2,13 +2,18 @@ import { z } from "zod/v4";
 
 z;
 
-// const schema = z.iso.datetime({ offset: true, local: true });
-// console.dir(schema.parse("2023-10-01T12:00:00.132"), { depth: null });
+// const time = z.iso.datetime();
+console.log("z.iso.datetime()");
+console.log(z.iso.datetime()._zod.def.pattern);
 
-const datetime = z.iso.datetime({ offset: true });
+console.log("z.iso.datetime({local: true})");
+console.log(z.iso.datetime({ local: true })._zod.def.pattern);
 
-datetime.parse("2020-01-01T00:00:00+02:00"); // ✅
-datetime.parse("2020-01-01T00:00:00.123+02:00"); // ✅ (millis optional)
-datetime.parse("2020-01-01T00:00:00.123+0200"); // ✅ (millis optional)
-datetime.parse("2020-01-01T00:00:00.123+02"); // ✅ (only offset hours)
-datetime.parse("2020-01-01T00:00:00Z"); // ✅ (Z still supported)
+console.log("z.iso.datetime({offset: true})");
+console.log(z.iso.datetime({ offset: true })._zod.def.pattern);
+
+console.log("z.iso.datetime({precision: z.TimePrecision.Minute})");
+console.log(z.iso.datetime({ precision: z.TimePrecision.Minute })._zod.def.pattern);
+
+console.log("z.iso.datetime({offset: true, local: true })");
+console.log(z.iso.datetime({ offset: true, local: true })._zod.def.pattern);
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 62d450cc..66151bba 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -59,6 +59,9 @@ importers:
       prettier:
         specifier: ^3.5.3
         version: 3.5.3
+      recheck:
+        specifier: ^4.5.0
+        version: 4.5.0
       semver:
         specifier: ^7.7.2
         version: 7.7.2
@@ -91,7 +94,7 @@ importers:
         version: link:packages/zod
       zod3:
         specifier: npm:zod@^3.0.0
-        version: zod@3.24.3
+        version: link:packages/zod
 
   packages/bench:
     devDependencies:
@@ -109,13 +112,13 @@ importers:
         version: zod@3.24.3
       zod4:
         specifier: npm:zod@latest
-        version: zod@3.25.53
+        version: link:../zod
 
   packages/docs:
     dependencies:
       '@inkeep/cxkit-react':
         specifier: ^0.5.80
-        version: 0.5.80(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@3.25.53)
+        version: 0.5.80(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@packages+zod)
       '@radix-ui/react-accordion':
         specifier: ^1.2.4
         version: 1.2.4(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -209,10 +212,10 @@ importers:
         version: link:../zod
       zod3:
         specifier: npm:zod@^3.24.0
-        version: zod@3.24.2
+        version: link:../zod
       zod4:
         specifier: npm:zod@^3.25.0
-        version: zod@3.25.34
+        version: link:../zod
 
   packages/tsc:
     devDependencies:
@@ -242,7 +245,7 @@ importers:
         version: link:../zod
       zod3:
         specifier: npm:zod@^3.0.0
-        version: zod@3.24.3
+        version: link:../zod
       zod3-24-2:
         specifier: npm:zod@3.24.2
         version: zod@3.24.2
@@ -1244,6 +1247,10 @@ packages:
     resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
     engines: {node: '>=14'}
 
+  '@pkgr/core@0.1.2':
+    resolution: {integrity: sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==}
+    engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+
   '@quansync/fs@0.1.3':
     resolution: {integrity: sha512-G0OnZbMWEs5LhDyqy2UL17vGhSVHkQIfVojMtEWVenvj0V5S84VBgy86kJIuNsGDp2p7sTKlpSIpBUWdC35OKg==}
     engines: {node: '>=20.0.0'}
@@ -4879,6 +4886,33 @@ packages:
     resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
     engines: {node: '>= 14.18.0'}
 
+  recheck-jar@4.5.0:
+    resolution: {integrity: sha512-Ad7oCQmY8cQLzd3QVNXjzZ+S6MbImGhR4AaW2yiGzteOfMV45522rt6nSzFyt8p3mCEaMcm/4MoZrMSxUcCbrA==}
+
+  recheck-linux-x64@4.5.0:
+    resolution: {integrity: sha512-52kXsR/v+IbGIKYYFZfSZcgse/Ci9IA2HnuzrtvRRcfODkcUGe4n72ESQ8nOPwrdHFg9i4j9/YyPh1HWWgpJ6A==}
+    cpu: [x64]
+    os: [linux]
+
+  recheck-macos-arm64@4.5.0:
+    resolution: {integrity: sha512-qIyK3dRuLkORQvv0b59fZZRXweSmjjWaoA4K8Kgifz0anMBH4pqsDV6plBlgjcRmW9yC12wErIRzifREaKnk2w==}
+    cpu: [arm64]
+    os: [darwin]
+
+  recheck-macos-x64@4.5.0:
+    resolution: {integrity: sha512-1wp/eiLxcjC/Ex4wurlrS/LGzt8IiF4TiK5sEjldu4HVAKdNCnnmsS9a5vFpfcikDz4ZuZlLlTi1VbQTxHlwZg==}
+    cpu: [x64]
+    os: [darwin]
+
+  recheck-windows-x64@4.5.0:
+    resolution: {integrity: sha512-ekBKwAp0oKkMULn5zgmHEYLwSJfkfb95AbTtbDkQazNkqYw9PRD/mVyFUR6Ff2IeRyZI0gxy+N2AKBISWydhug==}
+    cpu: [x64]
+    os: [win32]
+
+  recheck@4.5.0:
+    resolution: {integrity: sha512-kPnbOV6Zfx9a25AZ++28fI1q78L/UVRQmmuazwVRPfiiqpMs+WbOU69Shx820XgfKWfak0JH75PUvZMFtRGSsw==}
+    engines: {node: '>=20'}
+
   recma-build-jsx@1.0.0:
     resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==}
 
@@ -5289,6 +5323,10 @@ packages:
     engines: {node: 20 || >=22}
     hasBin: true
 
+  synckit@0.9.2:
+    resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+
   tailwind-merge@2.6.0:
     resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==}
 
@@ -5754,12 +5792,6 @@ packages:
   zod@3.24.3:
     resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==}
 
-  zod@3.25.34:
-    resolution: {integrity: sha512-lZHvSc2PpWdcfpHlyB33HA9nqP16GpC9IpiG4lYq9jZCJVLZNnWd6Y1cj79bcLSBKTkxepfpjckPv5Y5VOPlwA==}
-
-  zod@3.25.53:
-    resolution: {integrity: sha512-BKOKoY3XcGUVkqaalCtFK15LhwR0G0i65AClFpWSXLN2gJNBGlTktukHgwexCTa/dAacPPp9ReryXPWyeZF4LQ==}
-
   zod@4.0.0-beta.20250420T053007:
     resolution: {integrity: sha512-5pp8Q0PNDaNcUptGiBE9akyioJh3RJpagIxrLtAVMR9IxwcSZiOsJD/1/98CyhItdTlI2H91MfhhLzRlU+fifA==}
 
@@ -6234,7 +6266,7 @@ snapshots:
 
   '@inkeep/cxkit-color-mode@0.5.80': {}
 
-  '@inkeep/cxkit-primitives@0.5.80(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@3.25.53)':
+  '@inkeep/cxkit-primitives@0.5.80(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@packages+zod)':
     dependencies:
       '@inkeep/cxkit-color-mode': 0.5.80
       '@inkeep/cxkit-theme': 0.5.80
@@ -6268,7 +6300,7 @@ snapshots:
       lucide-react: 0.503.0(react@19.0.0)
       marked: 15.0.12
       merge-anything: 5.1.7
-      openai: 4.78.1(encoding@0.1.13)(zod@3.25.53)
+      openai: 4.78.1(encoding@0.1.13)(zod@packages+zod)
       prism-react-renderer: 2.4.1(react@19.0.0)
       react: 19.0.0
       react-dom: 19.0.0(react@19.0.0)
@@ -6289,9 +6321,9 @@ snapshots:
       - supports-color
       - zod
 
-  '@inkeep/cxkit-react@0.5.80(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@3.25.53)':
+  '@inkeep/cxkit-react@0.5.80(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@packages+zod)':
     dependencies:
-      '@inkeep/cxkit-styled': 0.5.80(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@3.25.53)
+      '@inkeep/cxkit-styled': 0.5.80(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@packages+zod)
       '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.11)(react@19.0.0)
       lucide-react: 0.503.0(react@19.0.0)
     transitivePeerDependencies:
@@ -6303,9 +6335,9 @@ snapshots:
       - supports-color
       - zod
 
-  '@inkeep/cxkit-styled@0.5.80(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@3.25.53)':
+  '@inkeep/cxkit-styled@0.5.80(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@packages+zod)':
     dependencies:
-      '@inkeep/cxkit-primitives': 0.5.80(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@3.25.53)
+      '@inkeep/cxkit-primitives': 0.5.80(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@packages+zod)
       class-variance-authority: 0.7.1
       clsx: 2.1.1
       merge-anything: 5.1.7
@@ -6640,6 +6672,8 @@ snapshots:
   '@pkgjs/parseargs@0.11.0':
     optional: true
 
+  '@pkgr/core@0.1.2': {}
+
   '@quansync/fs@0.1.3':
     dependencies:
       quansync: 0.2.10
@@ -10297,7 +10331,7 @@ snapshots:
       regex: 6.0.1
       regex-recursion: 6.0.2
 
-  openai@4.78.1(encoding@0.1.13)(zod@3.25.53):
+  openai@4.78.1(encoding@0.1.13)(zod@packages+zod):
     dependencies:
       '@types/node': 18.19.103
       '@types/node-fetch': 2.6.12
@@ -10307,7 +10341,7 @@ snapshots:
       formdata-node: 4.4.1
       node-fetch: 2.7.0(encoding@0.1.13)
     optionalDependencies:
-      zod: 3.25.53
+      zod: link:packages/zod
     transitivePeerDependencies:
       - encoding
 
@@ -10591,6 +10625,31 @@ snapshots:
 
   readdirp@4.1.2: {}
 
+  recheck-jar@4.5.0:
+    optional: true
+
+  recheck-linux-x64@4.5.0:
+    optional: true
+
+  recheck-macos-arm64@4.5.0:
+    optional: true
+
+  recheck-macos-x64@4.5.0:
+    optional: true
+
+  recheck-windows-x64@4.5.0:
+    optional: true
+
+  recheck@4.5.0:
+    dependencies:
+      synckit: 0.9.2
+    optionalDependencies:
+      recheck-jar: 4.5.0
+      recheck-linux-x64: 4.5.0
+      recheck-macos-arm64: 4.5.0
+      recheck-macos-x64: 4.5.0
+      recheck-windows-x64: 4.5.0
+
   recma-build-jsx@1.0.0:
     dependencies:
       '@types/estree': 1.0.6
@@ -11166,6 +11225,11 @@ snapshots:
       rimraf: 6.0.1
       tshy: 3.0.2
 
+  synckit@0.9.2:
+    dependencies:
+      '@pkgr/core': 0.1.2
+      tslib: 2.8.1
+
   tailwind-merge@2.6.0: {}
 
   tailwind-merge@3.0.2: {}
@@ -11629,10 +11693,6 @@ snapshots:
 
   zod@3.24.3: {}
 
-  zod@3.25.34: {}
-
-  zod@3.25.53: {}
-
   zod@4.0.0-beta.20250420T053007:
     dependencies:
       '@zod/core': 0.8.1


Test patch:
diff --git a/packages/zod/src/v4/classic/tests/continuability.test.ts b/packages/zod/src/v4/classic/tests/continuability.test.ts
new file mode 100644
index 00000000..f85ecd07
--- /dev/null
+++ b/packages/zod/src/v4/classic/tests/continuability.test.ts
@@ -0,0 +1,352 @@
+import { expect, test } from "vitest";
+import * as z from "zod/v4";
+
+test("continuability", () => {
+  /** 
+   *  | $ZodGUID
+  | $ZodUUID
+  | $ZodEmail
+  | $ZodURL
+  | $ZodEmoji
+  | $ZodNanoID
+  | $ZodCUID
+  | $ZodCUID2
+  | $ZodULID
+  | $ZodXID
+  | $ZodKSUID
+  | $ZodISODateTime
+  | $ZodISODate
+  | $ZodISOTime
+  | $ZodISODuration
+  | $ZodIPv4
+  | $ZodIPv6
+  | $ZodCIDRv4
+  | $ZodCIDRv6
+  | $ZodBase64
+  | $ZodBase64URL
+  | $ZodE164
+  | $ZodJWT;
+   */
+  expect(
+    z
+      .email()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "email",
+        "message": "Invalid email address",
+        "origin": "string",
+        "path": [],
+        "pattern": "/^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$/",
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .uuid()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "uuid",
+        "message": "Invalid UUID",
+        "origin": "string",
+        "path": [],
+        "pattern": "/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$/",
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .url()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "url",
+        "message": "Invalid URL",
+        "path": [],
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .jwt()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "jwt",
+        "message": "Invalid JWT",
+        "path": [],
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .cidrv4()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "cidrv4",
+        "message": "Invalid IPv4 range",
+        "origin": "string",
+        "path": [],
+        "pattern": "/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$/",
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .cidrv6()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "cidrv6",
+        "message": "Invalid IPv6 range",
+        "path": [],
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .ipv4()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "ipv4",
+        "message": "Invalid IPv4 address",
+        "origin": "string",
+        "path": [],
+        "pattern": "/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/",
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .ipv6()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "ipv6",
+        "message": "Invalid IPv6 address",
+        "path": [],
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .emoji()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "emoji",
+        "message": "Invalid emoji",
+        "origin": "string",
+        "path": [],
+        "pattern": "/^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$/u",
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .nanoid()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "nanoid",
+        "message": "Invalid nanoid",
+        "origin": "string",
+        "path": [],
+        "pattern": "/^[a-zA-Z0-9_-]{21}$/",
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .cuid()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "cuid",
+        "message": "Invalid cuid",
+        "origin": "string",
+        "path": [],
+        "pattern": "/^[cC][^\\s-]{8,}$/",
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .cuid2()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "cuid2",
+        "message": "Invalid cuid2",
+        "origin": "string",
+        "path": [],
+        "pattern": "/^[0-9a-z]+$/",
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .ulid()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "ulid",
+        "message": "Invalid ULID",
+        "origin": "string",
+        "path": [],
+        "pattern": "/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/",
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .xid()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "xid",
+        "message": "Invalid XID",
+        "origin": "string",
+        "path": [],
+        "pattern": "/^[0-9a-vA-V]{20}$/",
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+  expect(
+    z
+      .ksuid()
+      .refine(() => false)
+      .safeParse("invalid_value").error!.issues
+  ).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "ksuid",
+        "message": "Invalid KSUID",
+        "origin": "string",
+        "path": [],
+        "pattern": "/^[A-Za-z0-9]{27}$/",
+      },
+      {
+        "code": "custom",
+        "message": "Invalid input",
+        "path": [],
+      },
+    ]
+  `);
+});
diff --git a/packages/zod/src/v4/classic/tests/datetime.test.ts b/packages/zod/src/v4/classic/tests/datetime.test.ts
new file mode 100644
index 00000000..f78d48d4
--- /dev/null
+++ b/packages/zod/src/v4/classic/tests/datetime.test.ts
@@ -0,0 +1,296 @@
+import { checkSync } from "recheck";
+import { expect, test } from "vitest";
+import * as z from "zod/v4";
+
+test("basic datetime parsing", () => {
+  const datetime = z.string().datetime();
+  datetime.parse("1970-01-01T00:00:00.000Z");
+  datetime.parse("2022-10-13T09:52:31.816Z");
+  datetime.parse("2022-10-13T09:52:31.8162314Z");
+  datetime.parse("1970-01-01T00:00:00Z");
+  datetime.parse("2022-10-13T09:52:31Z");
+  expect(() => datetime.parse("")).toThrow();
+  expect(() => datetime.parse("foo")).toThrow();
+  expect(() => datetime.parse("2020-10-14")).toThrow();
+  expect(() => datetime.parse("T18:45:12.123")).toThrow();
+  expect(() => datetime.parse("2020-10-14T17:42:29+00:00")).toThrow();
+});
+
+test("datetime parsing with precision -1", () => {
+  const datetimeNoMs = z.string().datetime({ precision: -1, offset: true, local: true });
+  datetimeNoMs.parse("1970-01-01T00:00Z");
+  datetimeNoMs.parse("2022-10-13T09:52Z");
+  datetimeNoMs.parse("2022-10-13T09:52+02:00");
+
+  datetimeNoMs.parse("2022-10-13T09:52");
+  expect(() => datetimeNoMs.parse("tuna")).toThrow();
+  expect(() => datetimeNoMs.parse("2022-10-13T09:52+02")).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();
+});
+
+test("datetime parsing with precision 0", () => {
+  const datetimeNoMs = z.string().datetime({ precision: 0 });
+  datetimeNoMs.parse("1970-01-01T00:00:00Z");
+  datetimeNoMs.parse("2022-10-13T09:52:31Z");
+  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();
+});
+
+test("datetime parsing with precision 3", () => {
+  const datetime3Ms = z.string().datetime({ precision: 3 });
+  datetime3Ms.parse("1970-01-01T00:00:00.000Z");
+  datetime3Ms.parse("2022-10-13T09:52:31.123Z");
+  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();
+  expect(() => datetime3Ms.parse("2022-10-13T09:52:31Z")).toThrow();
+});
+
+test("datetime parsing with offset", () => {
+  const datetimeOffset = z.string().datetime({ offset: true });
+  datetimeOffset.parse("1970-01-01T00:00:00.000Z");
+  datetimeOffset.parse("2022-10-13T09:52:31.816234134Z");
+  datetimeOffset.parse("1970-01-01T00:00:00Z");
+  datetimeOffset.parse("2022-10-13T09:52:31.4Z");
+  datetimeOffset.parse("2020-10-14T17:42:29+00:00");
+  datetimeOffset.parse("2020-10-14T17:42:29+03:15");
+  expect(() => datetimeOffset.parse("2020-10-14T17:42:29+0315")).toThrow();
+  expect(() => datetimeOffset.parse("2020-10-14T17:42:29+03")).toThrow();
+  expect(() => datetimeOffset.parse("tuna")).toThrow();
+  expect(() => datetimeOffset.parse("2022-10-13T09:52:31.Z")).toThrow();
+});
+
+test("datetime parsing with offset and precision 0", () => {
+  const datetimeOffsetNoMs = z.string().datetime({ offset: true, precision: 0 });
+  datetimeOffsetNoMs.parse("1970-01-01T00:00:00Z");
+  datetimeOffsetNoMs.parse("2022-10-13T09:52:31Z");
+  datetimeOffsetNoMs.parse("2020-10-14T17:42:29+00:00");
+  expect(() => datetimeOffsetNoMs.parse("2020-10-14T17:42:29+0000")).toThrow();
+  expect(() => datetimeOffsetNoMs.parse("2020-10-14T17:42:29+00")).toThrow();
+  expect(() => datetimeOffsetNoMs.parse("tuna")).toThrow();
+  expect(() => datetimeOffsetNoMs.parse("1970-01-01T00:00:00.000Z")).toThrow();
+  expect(() => datetimeOffsetNoMs.parse("1970-01-01T00:00:00.Z")).toThrow();
+  expect(() => datetimeOffsetNoMs.parse("2022-10-13T09:52:31.816Z")).toThrow();
+  expect(() => datetimeOffsetNoMs.parse("2020-10-14T17:42:29.124+00:00")).toThrow();
+});
+
+test("datetime parsing with offset and precision 4", () => {
+  const datetimeOffset4Ms = z.string().datetime({ offset: true, precision: 4 });
+  datetimeOffset4Ms.parse("1970-01-01T00:00:00.1234Z");
+  datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+00:00");
+  expect(() => datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+0000")).toThrow();
+  expect(() => datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+00")).toThrow();
+  expect(() => datetimeOffset4Ms.parse("tuna")).toThrow();
+  expect(() => datetimeOffset4Ms.parse("1970-01-01T00:00:00.123Z")).toThrow();
+  expect(() => datetimeOffset4Ms.parse("2020-10-14T17:42:29.124+00:00")).toThrow();
+});
+
+test("datetime offset normalization", () => {
+  const a = z.iso.datetime({ offset: true });
+
+  expect(a.safeParse("2020-10-14T17:42:29+02")).toMatchObject({ success: false });
+  expect(a.safeParse("2020-10-14T17:42:29+0200")).toMatchObject({ success: false });
+  a.safeParse("2020-10-14T17:42:29+02:00");
+});
+
+test("datetime parsing with local option", () => {
+  const a = z.string().datetime({ local: true });
+
+  expect(a.safeParse("1970-01-01T00:00")).toMatchObject({ success: true });
+  expect(a.safeParse("1970-01-01T00:00:00")).toMatchObject({ success: true });
+  expect(a.safeParse("2022-10-13T09:52:31.816")).toMatchObject({ success: true });
+  expect(a.safeParse("1970-01-01T00:00:00.000")).toMatchObject({ success: true });
+  expect(a.safeParse("1970-01-01T00")).toMatchObject({ success: false });
+
+  // Should reject timezone indicators and invalid formats
+
+  expect(() => a.parse("2022-10-13T09:52:31+00:00")).toThrow();
+  expect(() => a.parse("2022-10-13 09:52:31")).toThrow();
+  expect(() => a.parse("2022-10-13T24:52:31")).toThrow();
+  expect(() => a.parse("2022-10-13T24:52")).toThrow();
+  expect(() => a.parse("2022-10-13T24:52Z")).toThrow();
+});
+
+test("datetime parsing with local and offset", () => {
+  const a = z.string().datetime({ local: true, offset: true });
+
+  // expect(a.parse("2022-10-13T12:52")).toEqual("2022-10-13T12:52:00");
+  a.parse("2022-10-13T12:52:00");
+  a.parse("2022-10-13T12:52:00Z");
+  a.parse("2022-10-13T12:52Z");
+  a.parse("2022-10-13T12:52");
+  a.parse("2022-10-13T12:52+02:00");
+  expect(() => a.parse("2022-10-13T12:52:00+02")).toThrow();
+  // expect(() => a.parse("2022-10-13T12:52Z")).toThrow();
+  // expect(() => a.parse("2022-10-13T12:52+02:00")).toThrow();
+});
+
+test("date parsing", () => {
+  const date = z.string().date();
+  date.parse("1970-01-01");
+  date.parse("2022-01-31");
+  date.parse("2022-03-31");
+  date.parse("2022-04-30");
+  date.parse("2022-05-31");
+  date.parse("2022-06-30");
+  date.parse("2022-07-31");
+  date.parse("2022-08-31");
+  date.parse("2022-09-30");
+  date.parse("2022-10-31");
+  date.parse("2022-11-30");
+  date.parse("2022-12-31");
+
+  date.parse("2000-02-29");
+  date.parse("2400-02-29");
+  expect(() => date.parse("2022-02-29")).toThrow();
+  expect(() => date.parse("2100-02-29")).toThrow();
+  expect(() => date.parse("2200-02-29")).toThrow();
+  expect(() => date.parse("2300-02-29")).toThrow();
+  expect(() => date.parse("2500-02-29")).toThrow();
+
+  expect(() => date.parse("")).toThrow();
+  expect(() => date.parse("foo")).toThrow();
+  expect(() => date.parse("200-01-01")).toThrow();
+  expect(() => date.parse("20000-01-01")).toThrow();
+  expect(() => date.parse("2000-0-01")).toThrow();
+  expect(() => date.parse("2000-011-01")).toThrow();
+  expect(() => date.parse("2000-01-0")).toThrow();
+  expect(() => date.parse("2000-01-011")).toThrow();
+  expect(() => date.parse("2000/01/01")).toThrow();
+  expect(() => date.parse("01-01-2022")).toThrow();
+  expect(() => date.parse("01/01/2022")).toThrow();
+  expect(() => date.parse("2000-01-01 00:00:00Z")).toThrow();
+  expect(() => date.parse("2020-10-14T17:42:29+00:00")).toThrow();
+  expect(() => date.parse("2020-10-14T17:42:29Z")).toThrow();
+  expect(() => date.parse("2020-10-14T17:42:29")).toThrow();
+  expect(() => date.parse("2020-10-14T17:42:29.123Z")).toThrow();
+
+  expect(() => date.parse("2000-00-12")).toThrow();
+  expect(() => date.parse("2000-12-00")).toThrow();
+  expect(() => date.parse("2000-01-32")).toThrow();
+  expect(() => date.parse("2000-13-01")).toThrow();
+  expect(() => date.parse("2000-21-01")).toThrow();
+
+  expect(() => date.parse("2000-02-30")).toThrow();
+  expect(() => date.parse("2000-02-31")).toThrow();
+  expect(() => date.parse("2000-04-31")).toThrow();
+  expect(() => date.parse("2000-06-31")).toThrow();
+  expect(() => date.parse("2000-09-31")).toThrow();
+  expect(() => date.parse("2000-11-31")).toThrow();
+});
+
+test("time parsing", () => {
+  const time = z.string().time();
+  time.parse("00:00:00");
+  time.parse("23:00:00");
+  time.parse("00:59:00");
+  time.parse("00:00:59");
+  time.parse("23:59:59");
+  time.parse("09:52:31");
+  time.parse("23:59:59.9999999");
+  time.parse("00:00");
+  expect(() => time.parse("")).toThrow();
+  expect(() => time.parse("foo")).toThrow();
+  expect(() => time.parse("00:00:00Z")).toThrow();
+  expect(() => time.parse("0:00:00")).toThrow();
+  expect(() => time.parse("00:0:00")).toThrow();
+  expect(() => time.parse("00:00:0")).toThrow();
+  expect(() => time.parse("00:00:00.000+00:00")).toThrow();
+  expect(() => time.parse("24:00:00")).toThrow();
+  expect(() => time.parse("00:60:00")).toThrow();
+  expect(() => time.parse("00:00:60")).toThrow();
+  expect(() => time.parse("24:60:60")).toThrow();
+
+  const time2 = z.string().time({ precision: 2 });
+  time2.parse("00:00:00.00");
+  time2.parse("09:52:31.12");
+  time2.parse("23:59:59.99");
+  expect(() => time2.parse("")).toThrow();
+  expect(() => time2.parse("foo")).toThrow();
+  expect(() => time2.parse("00:00:00")).toThrow();
+  expect(() => time2.parse("00:00:00.00Z")).toThrow();
+  expect(() => time2.parse("00:00:00.0")).toThrow();
+  expect(() => time2.parse("00:00:00.000")).toThrow();
+  expect(() => time2.parse("00:00:00.00+00:00")).toThrow();
+
+  const time3 = z.string().time({ precision: z.TimePrecision.Minute });
+  time3.parse("00:00");
+  expect(() => time3.parse("00:00:00")).toThrow();
+});
+
+test("duration", () => {
+  const duration = z.string().duration();
+
+  const validDurations = [
+    "P3Y6M4DT12H30M5S",
+    "P2Y9M3DT12H31M8.001S",
+    // "+P3Y6M4DT12H30M5S",
+    // "-PT0.001S",
+    // "+PT0.001S",
+    "PT0,001S",
+    "PT12H30M5S",
+    // "-P2M1D",
+    // "P-2M-1D",
+    // "-P5DT10H",
+    // "P-5DT-10H",
+    "P1Y",
+    "P2MT30M",
+    "PT6H",
+    "P5W",
+    // "P0.5Y",
+    // "P0,5Y",
+    // "P42YT7.004M",
+  ];
+
+  const invalidDurations = [
+    "foo bar",
+    "",
+    " ",
+    "P",
+    "PT",
+    "P1Y2MT",
+    "T1H",
+    "P0.5Y1D",
+    "P0,5Y6M",
+    "P1YT",
+    "P-2M-1D",
+    "P-5DT-10H",
+    "P1W2D",
+    "-P1D",
+  ];
+
+  for (const val of validDurations) {
+    const result = duration.safeParse(val);
+    if (!result.success) {
+      throw Error(`Valid duration could not be parsed: ${val}`);
+    }
+  }
+
+  for (const val of invalidDurations) {
+    const result = duration.safeParse(val);
+
+    if (result.success) {
+      throw Error(`Invalid duration was successful parsed: ${val}`);
+    }
+
+    expect(result.error.issues[0].message).toEqual("Invalid ISO duration");
+  }
+});
+
+test("redos checker", () => {
+  const a = z.iso.datetime();
+  const b = z.string().datetime({ offset: true });
+  const c = z.string().datetime({ local: true });
+  const d = z.string().datetime({ local: true, offset: true, precision: 3 });
+  const e = z.string().date();
+  const f = z.string().time();
+  const g = z.string().duration();
+  for (const schema of [a, b, c, d, e, f, g]) {
+    const result = checkSync(schema._zod.pattern.source, "");
+    if (result.status !== "safe") throw Error("ReDoS issue");
+  }
+});
diff --git a/packages/zod/src/v4/classic/tests/string.test.ts b/packages/zod/src/v4/classic/tests/string.test.ts
index 0de8bee5..cf1b9e13 100644
--- a/packages/zod/src/v4/classic/tests/string.test.ts
+++ b/packages/zod/src/v4/classic/tests/string.test.ts
@@ -298,35 +298,6 @@ test("jwt token", () => {
   // type isn't JWT
   const d5 = makeJwt({ typ: "SUP", alg: "HS256" }, { foo: "bar" });
   expect(() => jwt.parse(d5)).toThrow();
-
-  // const ONE_PART = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
-  // const NOT_BASE64 =
-  //   "headerIsNotBase64Encoded.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.RRi1X2IlXd5rZa9Mf_0VUOf-RxOzAhbB4tgViUGamWE";
-  // const NO_TYP =
-  //   "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.GuoUe6tw79bJlbU1HU0ADX0pr0u2kf3r_4OdrDufSfQ";
-  // const TYP_NOT_JWT =
-  //   "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpUVyJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.RRi1X2IlXd5rZa9Mf_0VUOf-RxOzAhbB4tgViUGamWE";
-
-  // const GOOD_JWT_HS256 =
-  //   "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
-  // const GOOD_JWT_ES256 =
-  //   "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.tyh-VfuzIxCyGYDlkBA7DfyjrqmSHu6pQ2hoZuFqUSLPNY2N0mpHb3nk5K17HWP_3cYHBw7AhHale5wky6-sVA";
-
-  // const jwtSchema = z.string().jwt();
-
-  // expect(() => jwtSchema.parse(ONE_PART)).toThrow();
-  // expect(() => jwtSchema.parse(NOT_BASE64)).toThrow();
-  // expect(() => jwtSchema.parse(TYP_NOT_JWT)).toThrow();
-  // expect(() => jwtSchema.parse(TYP_NOT_JWT)).toThrow();
-  // expect(() => jwtSchema.parse(TYP_NOT_JWT)).toThrow();
-  // expect(() => z.string().jwt({ alg: "ES256" }).parse(GOOD_JWT_HS256)).toThrow();
-  // expect(() => z.string().jwt({ alg: "HS256" }).parse(GOOD_JWT_ES256)).toThrow();
-  // //Success
-  // jwtSchema.parse(NO_TYP); // allow no typ
-  // expect(() => jwtSchema.parse(GOOD_JWT_HS256)).not.toThrow();
-  // expect(() => jwtSchema.parse(GOOD_JWT_ES256)).not.toThrow();
-  // expect(() => z.string().jwt({ alg: "HS256" }).parse(GOOD_JWT_HS256)).not.toThrow();
-  // expect(() => z.string().jwt({ alg: "ES256" }).parse(GOOD_JWT_ES256)).not.toThrow();
 });
 
 test("url validations", () => {
@@ -753,232 +724,6 @@ test("lowerCase", () => {
   expect(z.string().toUpperCase().parse("asdf")).toEqual("ASDF");
 });
 
-test("datetime parsing", () => {
-  const datetime = z.string().datetime();
-  datetime.parse("1970-01-01T00:00:00.000Z");
-  datetime.parse("2022-10-13T09:52:31.816Z");
-  datetime.parse("2022-10-13T09:52:31.8162314Z");
-  datetime.parse("1970-01-01T00:00:00Z");
-  datetime.parse("2022-10-13T09:52:31Z");
-  expect(() => datetime.parse("")).toThrow();
-  expect(() => datetime.parse("foo")).toThrow();
-  expect(() => datetime.parse("2020-10-14")).toThrow();
-  expect(() => datetime.parse("T18:45:12.123")).toThrow();
-  expect(() => datetime.parse("2020-10-14T17:42:29+00:00")).toThrow();
-
-  const datetimeNoMs = z.string().datetime({ precision: 0 });
-  datetimeNoMs.parse("1970-01-01T00:00:00Z");
-  datetimeNoMs.parse("2022-10-13T09:52:31Z");
-  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("2022-10-13T09:52:31.123Z");
-  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();
-  expect(() => datetime3Ms.parse("2022-10-13T09:52:31Z")).toThrow();
-
-  const datetimeOffset = z.string().datetime({ offset: true });
-  datetimeOffset.parse("1970-01-01T00:00:00.000Z");
-  datetimeOffset.parse("2022-10-13T09:52:31.816234134Z");
-  datetimeOffset.parse("1970-01-01T00:00:00Z");
-  datetimeOffset.parse("2022-10-13T09:52:31.4Z");
-  datetimeOffset.parse("2020-10-14T17:42:29+00:00");
-  datetimeOffset.parse("2020-10-14T17:42:29+03:15");
-  datetimeOffset.parse("2020-10-14T17:42:29+0315");
-  datetimeOffset.parse("2020-10-14T17:42:29+03");
-  expect(() => datetimeOffset.parse("tuna")).toThrow();
-  expect(() => datetimeOffset.parse("2022-10-13T09:52:31.Z")).toThrow();
-
-  const datetimeOffsetNoMs = z.string().datetime({ offset: true, precision: 0 });
-  datetimeOffsetNoMs.parse("1970-01-01T00:00:00Z");
-  datetimeOffsetNoMs.parse("2022-10-13T09:52:31Z");
-  datetimeOffsetNoMs.parse("2020-10-14T17:42:29+00:00");
-  datetimeOffsetNoMs.parse("2020-10-14T17:42:29+0000");
-  datetimeOffsetNoMs.parse("2020-10-14T17:42:29+00");
-  expect(() => datetimeOffsetNoMs.parse("tuna")).toThrow();
-  expect(() => datetimeOffsetNoMs.parse("1970-01-01T00:00:00.000Z")).toThrow();
-  expect(() => datetimeOffsetNoMs.parse("1970-01-01T00:00:00.Z")).toThrow();
-  expect(() => datetimeOffsetNoMs.parse("2022-10-13T09:52:31.816Z")).toThrow();
-  expect(() => datetimeOffsetNoMs.parse("2020-10-14T17:42:29.124+00:00")).toThrow();
-
-  const datetimeOffset4Ms = z.string().datetime({ offset: true, precision: 4 });
-  datetimeOffset4Ms.parse("1970-01-01T00:00:00.1234Z");
-  datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+00:00");
-  datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+0000");
-  datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+00");
-  expect(() => datetimeOffset4Ms.parse("tuna")).toThrow();
-  expect(() => datetimeOffset4Ms.parse("1970-01-01T00:00:00.123Z")).toThrow();
-  expect(() => datetimeOffset4Ms.parse("2020-10-14T17:42:29.124+00:00")).toThrow();
-});
-
-test("datetime offset normalization", () => {
-  const a = z.iso.datetime({ offset: true });
-  expect({
-    a: a.parse("2020-10-14T17:42:29+02"),
-    b: a.parse("2020-10-14T17:42:29+0200"),
-    c: a.parse("2020-10-14T17:42:29+02:00"),
-  }).toMatchInlineSnapshot(`
-    {
-      "a": "2020-10-14T17:42:29+02:00",
-      "b": "2020-10-14T17:42:29+02:00",
-      "c": "2020-10-14T17:42:29+02:00",
-    }
-  `);
-});
-
-test("date parsing", () => {
-  const date = z.string().date();
-  date.parse("1970-01-01");
-  date.parse("2022-01-31");
-  date.parse("2022-03-31");
-  date.parse("2022-04-30");
-  date.parse("2022-05-31");
-  date.parse("2022-06-30");
-  date.parse("2022-07-31");
-  date.parse("2022-08-31");
-  date.parse("2022-09-30");
-  date.parse("2022-10-31");
-  date.parse("2022-11-30");
-  date.parse("2022-12-31");
-
-  date.parse("2000-02-29");
-  date.parse("2400-02-29");
-  expect(() => date.parse("2022-02-29")).toThrow();
-  expect(() => date.parse("2100-02-29")).toThrow();
-  expect(() => date.parse("2200-02-29")).toThrow();
-  expect(() => date.parse("2300-02-29")).toThrow();
-  expect(() => date.parse("2500-02-29")).toThrow();
-
-  expect(() => date.parse("")).toThrow();
-  expect(() => date.parse("foo")).toThrow();
-  expect(() => date.parse("200-01-01")).toThrow();
-  expect(() => date.parse("20000-01-01")).toThrow();
-  expect(() => date.parse("2000-0-01")).toThrow();
-  expect(() => date.parse("2000-011-01")).toThrow();
-  expect(() => date.parse("2000-01-0")).toThrow();
-  expect(() => date.parse("2000-01-011")).toThrow();
-  expect(() => date.parse("2000/01/01")).toThrow();
-  expect(() => date.parse("01-01-2022")).toThrow();
-  expect(() => date.parse("01/01/2022")).toThrow();
-  expect(() => date.parse("2000-01-01 00:00:00Z")).toThrow();
-  expect(() => date.parse("2020-10-14T17:42:29+00:00")).toThrow();
-  expect(() => date.parse("2020-10-14T17:42:29Z")).toThrow();
-  expect(() => date.parse("2020-10-14T17:42:29")).toThrow();
-  expect(() => date.parse("2020-10-14T17:42:29.123Z")).toThrow();
-
-  expect(() => date.parse("2000-00-12")).toThrow();
-  expect(() => date.parse("2000-12-00")).toThrow();
-  expect(() => date.parse("2000-01-32")).toThrow();
-  expect(() => date.parse("2000-13-01")).toThrow();
-  expect(() => date.parse("2000-21-01")).toThrow();
-
-  expect(() => date.parse("2000-02-30")).toThrow();
-  expect(() => date.parse("2000-02-31")).toThrow();
-  expect(() => date.parse("2000-04-31")).toThrow();
-  expect(() => date.parse("2000-06-31")).toThrow();
-  expect(() => date.parse("2000-09-31")).toThrow();
-  expect(() => date.parse("2000-11-31")).toThrow();
-});
-
-test("time parsing", () => {
-  const time = z.string().time();
-  time.parse("00:00:00");
-  time.parse("23:00:00");
-  time.parse("00:59:00");
-  time.parse("00:00:59");
-  time.parse("23:59:59");
-  time.parse("09:52:31");
-  time.parse("23:59:59.9999999");
-  expect(() => time.parse("")).toThrow();
-  expect(() => time.parse("foo")).toThrow();
-  expect(() => time.parse("00:00:00Z")).toThrow();
-  expect(() => time.parse("0:00:00")).toThrow();
-  expect(() => time.parse("00:0:00")).toThrow();
-  expect(() => time.parse("00:00:0")).toThrow();
-  expect(() => time.parse("00:00:00.000+00:00")).toThrow();
-
-  expect(() => time.parse("24:00:00")).toThrow();
-  expect(() => time.parse("00:60:00")).toThrow();
-  expect(() => time.parse("00:00:60")).toThrow();
-  expect(() => time.parse("24:60:60")).toThrow();
-
-  const time2 = z.string().time({ precision: 2 });
-  time2.parse("00:00:00.00");
-  time2.parse("09:52:31.12");
-  time2.parse("23:59:59.99");
-  expect(() => time2.parse("")).toThrow();
-  expect(() => time2.parse("foo")).toThrow();
-  expect(() => time2.parse("00:00:00")).toThrow();
-  expect(() => time2.parse("00:00:00.00Z")).toThrow();
-  expect(() => time2.parse("00:00:00.0")).toThrow();
-  expect(() => time2.parse("00:00:00.000")).toThrow();
-  expect(() => time2.parse("00:00:00.00+00:00")).toThrow();
-});
-
-test("duration", () => {
-  const duration = z.string().duration();
-
-  const validDurations = [
-    "P3Y6M4DT12H30M5S",
-    "P2Y9M3DT12H31M8.001S",
-    // "+P3Y6M4DT12H30M5S",
-    // "-PT0.001S",
-    // "+PT0.001S",
-    "PT0,001S",
-    "PT12H30M5S",
-    // "-P2M1D",
-    // "P-2M-1D",
-    // "-P5DT10H",
-    // "P-5DT-10H",
-    "P1Y",
-    "P2MT30M",
-    "PT6H",
-    "P5W",
-    // "P0.5Y",
-    // "P0,5Y",
-    // "P42YT7.004M",
-  ];
-
-  const invalidDurations = [
-    "foo bar",
-    "",
-    " ",
-    "P",
-    "PT",
-    "P1Y2MT",
-    "T1H",
-    "P0.5Y1D",
-    "P0,5Y6M",
-    "P1YT",
-    "P-2M-1D",
-    "P-5DT-10H",
-    "P1W2D",
-    "-P1D",
-  ];
-
-  for (const val of validDurations) {
-    const result = duration.safeParse(val);
-    if (!result.success) {
-      throw Error(`Valid duration could not be parsed: ${val}`);
-    }
-  }
-
-  for (const val of invalidDurations) {
-    const result = duration.safeParse(val);
-
-    if (result.success) {
-      throw Error(`Invalid duration was successful parsed: ${val}`);
-    }
-
-    expect(result.error.issues[0].message).toEqual("Invalid ISO duration");
-  }
-});
-
 // test("IP validation", () => {
 //   const ipSchema = z.string().ip();
 
@@ -1134,353 +879,3 @@ test("E.164 validation", () => {
   expect(validE164Numbers.every((number) => e164Number.safeParse(number).success)).toBe(true);
   expect(invalidE164Numbers.every((number) => e164Number.safeParse(number).success === false)).toBe(true);
 });
-
-test("continuability", () => {
-  /** 
-   *  | $ZodGUID
-  | $ZodUUID
-  | $ZodEmail
-  | $ZodURL
-  | $ZodEmoji
-  | $ZodNanoID
-  | $ZodCUID
-  | $ZodCUID2
-  | $ZodULID
-  | $ZodXID
-  | $ZodKSUID
-  | $ZodISODateTime
-  | $ZodISODate
-  | $ZodISOTime
-  | $ZodISODuration
-  | $ZodIPv4
-  | $ZodIPv6
-  | $ZodCIDRv4
-  | $ZodCIDRv6
-  | $ZodBase64
-  | $ZodBase64URL
-  | $ZodE164
-  | $ZodJWT;
-   */
-  expect(
-    z
-      .email()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "email",
-        "message": "Invalid email address",
-        "origin": "string",
-        "path": [],
-        "pattern": "/^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$/",
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .uuid()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "uuid",
-        "message": "Invalid UUID",
-        "origin": "string",
-        "path": [],
-        "pattern": "/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$/",
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .url()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "url",
-        "message": "Invalid URL",
-        "path": [],
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .jwt()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "jwt",
-        "message": "Invalid JWT",
-        "path": [],
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .cidrv4()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "cidrv4",
-        "message": "Invalid IPv4 range",
-        "origin": "string",
-        "path": [],
-        "pattern": "/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$/",
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .cidrv6()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "cidrv6",
-        "message": "Invalid IPv6 range",
-        "path": [],
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .ipv4()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "ipv4",
-        "message": "Invalid IPv4 address",
-        "origin": "string",
-        "path": [],
-        "pattern": "/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/",
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .ipv6()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "ipv6",
-        "message": "Invalid IPv6 address",
-        "path": [],
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .emoji()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "emoji",
-        "message": "Invalid emoji",
-        "origin": "string",
-        "path": [],
-        "pattern": "/^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$/u",
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .nanoid()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "nanoid",
-        "message": "Invalid nanoid",
-        "origin": "string",
-        "path": [],
-        "pattern": "/^[a-zA-Z0-9_-]{21}$/",
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .cuid()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "cuid",
-        "message": "Invalid cuid",
-        "origin": "string",
-        "path": [],
-        "pattern": "/^[cC][^\\s-]{8,}$/",
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .cuid2()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "cuid2",
-        "message": "Invalid cuid2",
-        "origin": "string",
-        "path": [],
-        "pattern": "/^[0-9a-z]+$/",
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .ulid()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "ulid",
-        "message": "Invalid ULID",
-        "origin": "string",
-        "path": [],
-        "pattern": "/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/",
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .xid()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "xid",
-        "message": "Invalid XID",
-        "origin": "string",
-        "path": [],
-        "pattern": "/^[0-9a-vA-V]{20}$/",
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-  expect(
-    z
-      .ksuid()
-      .refine(() => false)
-      .safeParse("invalid_value").error!.issues
-  ).toMatchInlineSnapshot(`
-    [
-      {
-        "code": "invalid_format",
-        "format": "ksuid",
-        "message": "Invalid KSUID",
-        "origin": "string",
-        "path": [],
-        "pattern": "/^[A-Za-z0-9]{27}$/",
-      },
-      {
-        "code": "custom",
-        "message": "Invalid input",
-        "path": [],
-      },
-    ]
-  `);
-});
diff --git a/packages/zod/src/v4/classic/tests/template-literal.test.ts b/packages/zod/src/v4/classic/tests/template-literal.test.ts
index e46dccdf..17e3a689 100644
--- a/packages/zod/src/v4/classic/tests/template-literal.test.ts
+++ b/packages/zod/src/v4/classic/tests/template-literal.test.ts
@@ -551,7 +551,7 @@ test("regexes", () => {
   expect(cuidZZZ._zod.pattern.source).toMatchInlineSnapshot(`"^[cC][^\\s-]{8,}ZZZ$"`);
   expect(cuid2._zod.pattern.source).toMatchInlineSnapshot(`"^[0-9a-z]+$"`);
   expect(datetime._zod.pattern.source).toMatchInlineSnapshot(
-    `"^((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))T([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(\\.\\d+)?(Z)$"`
+    `"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"`
   );
   expect(email._zod.pattern.source).toMatchInlineSnapshot(
     `"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"`
diff --git a/packages/zod/src/v4/classic/tests/to-json-schema.test.ts b/packages/zod/src/v4/classic/tests/to-json-schema.test.ts
index 7c32b036..3e7284fe 100644
--- a/packages/zod/src/v4/classic/tests/to-json-schema.test.ts
+++ b/packages/zod/src/v4/classic/tests/to-json-schema.test.ts
@@ -62,7 +62,7 @@ describe("toJSONSchema", () => {
       {
         "$schema": "https://json-schema.org/draft/2020-12/schema",
         "format": "date-time",
-        "pattern": "^((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))T([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(\\.\\d+)?(Z)$",
+        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
         "type": "string",
       }
     `);
@@ -70,7 +70,7 @@ describe("toJSONSchema", () => {
       {
         "$schema": "https://json-schema.org/draft/2020-12/schema",
         "format": "date",
-        "pattern": "^((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))$",
+        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
         "type": "string",
       }
     `);
@@ -78,7 +78,7 @@ describe("toJSONSchema", () => {
       {
         "$schema": "https://json-schema.org/draft/2020-12/schema",
         "format": "time",
-        "pattern": "^([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(\\.\\d+)?$",
+        "pattern": "^(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?$",
         "type": "string",
       }
     `);
@@ -277,7 +277,7 @@ describe("toJSONSchema", () => {
       {
         "$schema": "https://json-schema.org/draft/2020-12/schema",
         "format": "date-time",
-        "pattern": "^((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))T([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(\\.\\d+)?(Z)$",
+        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
         "type": "string",
       }
     `);
@@ -286,7 +286,7 @@ describe("toJSONSchema", () => {
       {
         "$schema": "https://json-schema.org/draft/2020-12/schema",
         "format": "date",
-        "pattern": "^((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))$",
+        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
         "type": "string",
       }
     `);
@@ -294,7 +294,7 @@ describe("toJSONSchema", () => {
       {
         "$schema": "https://json-schema.org/draft/2020-12/schema",
         "format": "time",
-        "pattern": "^([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(\\.\\d+)?$",
+        "pattern": "^(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?$",
         "type": "string",
       }
     `);