Repository: samchungy/zod-openapi (ts)

Issue:
Default string format setting for ZodDate
Thanks for creating a nice library😄

When converting a ZodDate to an openapi schema, the type is a string, and the format is unset and fixed.
However, regarding format, if there is one format that works best for one project, it would be somewhat redundant to set the format with the openapi function every time.

So what do you think about allowing pre-set default values for this format?
If this is a good suggestion, I would like to figure out how to modify it.

Pull request:
Add default date schema option
closed https://github.com/samchungy/zod-openapi/issues/305

Hi samchungy.

I have added a feature that resolves #305.

Added an options object argument to createDocument function to allow setting the value of  `defaultDateSchema`.
After the SchemaState object is created, it is passed to each function by passing an options object to SchemaState object.

If you see any problems or shortcomings, please point them out to me.

Patch:
diff --git a/README.md b/README.md
index 3f009d1..7377f4c 100644
--- a/README.md
+++ b/README.md
@@ -198,6 +198,14 @@ const document = createDocument({
   ```
 </details>
 
+`createDocument` takes an optional `CreateDocumentOptions` argument which can be used to modify how the document is created.
+
+```typescript
+const document = createDocument(details, {
+  defaultDateSchema: { type: 'string', format: 'date-time' }, // defaults to { type: 'string' }
+});
+```
+
 ### Request Parameters
 
 Query, Path, Header & Cookie parameters can be created using the `requestParams` key under the `method` key as follows:
diff --git a/src/create/callbacks.ts b/src/create/callbacks.ts
index f284a01..ea83f47 100644
--- a/src/create/callbacks.ts
+++ b/src/create/callbacks.ts
@@ -4,7 +4,10 @@ import {
   type ComponentsObject,
   createComponentCallbackRef,
 } from './components';
-import type { ZodOpenApiCallbackObject } from './document';
+import type {
+  CreateDocumentOptions,
+  ZodOpenApiCallbackObject,
+} from './document';
 import { createPathItem } from './paths';
 import { isISpecificationExtension } from './specificationExtension';
 
@@ -12,6 +15,7 @@ export const createCallback = (
   callbackObject: ZodOpenApiCallbackObject,
   components: ComponentsObject,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): oas31.CallbackObject => {
   const { ref, ...callbacks } = callbackObject;
 
@@ -24,11 +28,13 @@ export const createCallback = (
       return acc;
     }
 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
-    acc[callbackName] = createPathItem(pathItemObject, components, [
-      ...subpath,
-      callbackName,
-    ]);
+    acc[callbackName] = createPathItem(
+      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
+      pathItemObject,
+      components,
+      [...subpath, callbackName],
+      documentOptions,
+    );
     return acc;
   }, {});
 
@@ -50,6 +56,7 @@ export const createCallbacks = (
   callbacksObject: oas31.CallbackObject | undefined,
   components: ComponentsObject,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): oas31.CallbackObject | undefined => {
   if (!callbacksObject) {
     return undefined;
@@ -61,11 +68,14 @@ export const createCallbacks = (
         acc[callbackName] = callbackObject;
         return acc;
       }
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
-      acc[callbackName] = createCallback(callbackObject, components, [
-        ...subpath,
-        callbackName,
-      ]);
+
+      acc[callbackName] = createCallback(
+        // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
+        callbackObject,
+        components,
+        [...subpath, callbackName],
+        documentOptions,
+      );
       return acc;
     },
     {},
diff --git a/src/create/components.ts b/src/create/components.ts
index 50ce6a2..5531da9 100644
--- a/src/create/components.ts
+++ b/src/create/components.ts
@@ -5,6 +5,7 @@ import { isAnyZodType } from '../zodType';
 
 import { createCallback } from './callbacks';
 import type {
+  CreateDocumentOptions,
   ZodOpenApiCallbackObject,
   ZodOpenApiComponentsObject,
   ZodOpenApiRequestBodyObject,
@@ -399,16 +400,35 @@ export const createComponentCallbackRef = (callbackRef: string) =>
 export const createComponents = (
   componentsObject: ZodOpenApiComponentsObject,
   components: ComponentsObject,
+  documentOptions?: CreateDocumentOptions,
 ): oas31.ComponentsObject | undefined => {
-  const combinedSchemas = createSchemaComponents(componentsObject, components);
+  const combinedSchemas = createSchemaComponents(
+    componentsObject,
+    components,
+    documentOptions,
+  );
   const combinedParameters = createParamComponents(
     componentsObject,
     components,
+    documentOptions,
+  );
+  const combinedHeaders = createHeaderComponents(
+    componentsObject,
+    components,
+    documentOptions,
+  );
+  const combinedResponses = createResponseComponents(
+    components,
+    documentOptions,
+  );
+  const combinedRequestBodies = createRequestBodiesComponents(
+    components,
+    documentOptions,
+  );
+  const combinedCallbacks = createCallbackComponents(
+    components,
+    documentOptions,
   );
-  const combinedHeaders = createHeaderComponents(componentsObject, components);
-  const combinedResponses = createResponseComponents(components);
-  const combinedRequestBodies = createRequestBodiesComponents(components);
-  const combinedCallbacks = createCallbackComponents(components);
 
   const { schemas, parameters, headers, responses, requestBodies, ...rest } =
     componentsObject;
@@ -428,6 +448,7 @@ export const createComponents = (
 const createSchemaComponents = (
   componentsObject: ZodOpenApiComponentsObject,
   components: ComponentsObject,
+  documentOptions?: CreateDocumentOptions,
 ): oas31.ComponentsObject['schemas'] => {
   Array.from(components.schemas).forEach(([schema, { type }], index) => {
     if (type === 'manual') {
@@ -436,6 +457,7 @@ const createSchemaComponents = (
         type: schema._def.openapi?.refType ?? 'output',
         path: [],
         visited: new Set(),
+        documentOptions,
       };
 
       createSchema(schema, state, [`component schema index ${index}`]);
@@ -479,6 +501,7 @@ const createSchemaComponents = (
 const createParamComponents = (
   componentsObject: ZodOpenApiComponentsObject,
   components: ComponentsObject,
+  documentOptions?: CreateDocumentOptions,
 ): oas31.ComponentsObject['parameters'] => {
   Array.from(components.parameters).forEach(([schema, component], index) => {
     if (component.type === 'manual') {
@@ -486,6 +509,7 @@ const createParamComponents = (
         schema,
         components,
         [`component parameter index ${index}`],
+        documentOptions,
         component.in,
         component.ref,
       );
@@ -527,10 +551,11 @@ const createParamComponents = (
 const createHeaderComponents = (
   componentsObject: ZodOpenApiComponentsObject,
   components: ComponentsObject,
+  documentOptions?: CreateDocumentOptions,
 ): oas31.ComponentsObject['headers'] => {
   Array.from(components.headers).forEach(([schema, component]) => {
     if (component.type === 'manual') {
-      createHeaderOrRef(schema, components);
+      createHeaderOrRef(schema, components, documentOptions);
     }
   });
 
@@ -566,10 +591,16 @@ const createHeaderComponents = (
 
 const createResponseComponents = (
   components: ComponentsObject,
+  documentOptions?: CreateDocumentOptions,
 ): oas31.ComponentsObject['responses'] => {
   Array.from(components.responses).forEach(([schema, component], index) => {
     if (component.type === 'manual') {
-      createResponse(schema, components, [`component response index ${index}`]);
+      createResponse(
+        schema,
+        components,
+        [`component response index ${index}`],
+        documentOptions,
+      );
     }
   });
 
@@ -591,12 +622,16 @@ const createResponseComponents = (
 
 const createRequestBodiesComponents = (
   components: ComponentsObject,
+  documentOptions?: CreateDocumentOptions,
 ): oas31.ComponentsObject['requestBodies'] => {
   Array.from(components.requestBodies).forEach(([schema, component], index) => {
     if (component.type === 'manual') {
-      createRequestBody(schema, components, [
-        `component request body ${index}`,
-      ]);
+      createRequestBody(
+        schema,
+        components,
+        [`component request body ${index}`],
+        documentOptions,
+      );
     }
   });
 
@@ -619,10 +654,16 @@ const createRequestBodiesComponents = (
 
 const createCallbackComponents = (
   components: ComponentsObject,
+  documentOptions?: CreateDocumentOptions,
 ): oas31.ComponentsObject['callbacks'] => {
   Array.from(components.callbacks).forEach(([schema, component], index) => {
     if (component.type === 'manual') {
-      createCallback(schema, components, [`component callback ${index}`]);
+      createCallback(
+        schema,
+        components,
+        [`component callback ${index}`],
+        documentOptions,
+      );
     }
   });
 
diff --git a/src/create/content.ts b/src/create/content.ts
index f108f34..e8f7b43 100644
--- a/src/create/content.ts
+++ b/src/create/content.ts
@@ -5,6 +5,7 @@ import { isAnyZodType } from '../zodType';
 
 import type { ComponentsObject, CreationType } from './components';
 import type {
+  CreateDocumentOptions,
   ZodOpenApiContentObject,
   ZodOpenApiMediaTypeObject,
 } from './document';
@@ -19,6 +20,7 @@ export const createMediaTypeSchema = (
   components: ComponentsObject,
   type: CreationType,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): oas31.SchemaObject | oas31.ReferenceObject | undefined => {
   if (!schemaObject) {
     return undefined;
@@ -35,6 +37,7 @@ export const createMediaTypeSchema = (
       type,
       path: [],
       visited: new Set(),
+      documentOptions,
     },
     subpath,
   );
@@ -45,6 +48,7 @@ const createMediaTypeObject = (
   components: ComponentsObject,
   type: CreationType,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): oas31.MediaTypeObject | undefined => {
   if (!mediaTypeObject) {
     return undefined;
@@ -52,10 +56,13 @@ const createMediaTypeObject = (
 
   return {
     ...mediaTypeObject,
-    schema: createMediaTypeSchema(mediaTypeObject.schema, components, type, [
-      ...subpath,
-      'schema',
-    ]),
+    schema: createMediaTypeSchema(
+      mediaTypeObject.schema,
+      components,
+      type,
+      [...subpath, 'schema'],
+      documentOptions,
+    ),
   };
 };
 
@@ -64,6 +71,7 @@ export const createContent = (
   components: ComponentsObject,
   type: CreationType,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): oas31.ContentObject =>
   Object.entries(contentObject).reduce<oas31.ContentObject>(
     (acc, [mediaType, zodOpenApiMediaTypeObject]): oas31.ContentObject => {
@@ -72,6 +80,7 @@ export const createContent = (
         components,
         type,
         [...subpath, mediaType],
+        documentOptions,
       );
 
       if (mediaTypeObject) {
diff --git a/src/create/document.ts b/src/create/document.ts
index d696998..8ffe237 100644
--- a/src/create/document.ts
+++ b/src/create/document.ts
@@ -154,8 +154,13 @@ export type ZodObjectInputType<
   Input = Record<string, unknown>,
 > = ZodType<Output, Def, Input>;
 
+export interface CreateDocumentOptions {
+  defaultDateSchema?: Pick<oas31.SchemaObject, 'type' | 'format'>;
+}
+
 export const createDocument = (
   zodOpenApiObject: ZodOpenApiObject,
+  documentOptions?: CreateDocumentOptions,
 ): oas31.OpenAPIObject => {
   const { paths, webhooks, components = {}, ...rest } = zodOpenApiObject;
   const defaultComponents = getDefaultComponents(
@@ -163,9 +168,17 @@ export const createDocument = (
     zodOpenApiObject.openapi,
   );
 
-  const createdPaths = createPaths(paths, defaultComponents);
-  const createdWebhooks = createPaths(webhooks, defaultComponents);
-  const createdComponents = createComponents(components, defaultComponents);
+  const createdPaths = createPaths(paths, defaultComponents, documentOptions);
+  const createdWebhooks = createPaths(
+    webhooks,
+    defaultComponents,
+    documentOptions,
+  );
+  const createdComponents = createComponents(
+    components,
+    defaultComponents,
+    documentOptions,
+  );
 
   return {
     ...rest,
diff --git a/src/create/parameters.ts b/src/create/parameters.ts
index c0cf623..482238f 100644
--- a/src/create/parameters.ts
+++ b/src/create/parameters.ts
@@ -4,7 +4,11 @@ import type { oas30, oas31 } from '../openapi3-ts/dist';
 import { isAnyZodType, isZodType } from '../zodType';
 
 import type { ComponentsObject } from './components';
-import type { ZodObjectInputType, ZodOpenApiParameters } from './document';
+import type {
+  CreateDocumentOptions,
+  ZodObjectInputType,
+  ZodOpenApiParameters,
+} from './document';
 import { type SchemaState, createSchema } from './schema';
 import { isOptionalSchema } from './schema/parsers/optional';
 
@@ -15,6 +19,7 @@ export const createBaseParameter = (
   schema: ZodType,
   components: ComponentsObject,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): oas31.BaseParameterObject => {
   const { ref, ...rest } = schema._def.openapi?.param ?? {};
   const state: SchemaState = {
@@ -22,6 +27,7 @@ export const createBaseParameter = (
     type: 'input',
     path: [],
     visited: new Set(),
+    documentOptions,
   };
   const schemaObject = createSchema(schema, state, [...subpath, 'schema']);
   const required = !isOptionalSchema(schema, state)?.optional;
@@ -40,6 +46,7 @@ export const createParamOrRef = (
   zodSchema: ZodType,
   components: ComponentsObject,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
   type?: keyof ZodOpenApiParameters,
   name?: string,
 ): oas31.ParameterObject | oas31.ReferenceObject => {
@@ -69,7 +76,12 @@ export const createParamOrRef = (
   }
 
   // Optional Objects can return a reference object
-  const baseParamOrRef = createBaseParameter(zodSchema, components, subpath);
+  const baseParamOrRef = createBaseParameter(
+    zodSchema,
+    components,
+    subpath,
+    documentOptions,
+  );
   if ('$ref' in baseParamOrRef) {
     throw new Error('Unexpected Error: received a reference object');
   }
@@ -104,6 +116,7 @@ const createParameters = (
   zodObjectType: ZodObjectInputType | undefined,
   components: ComponentsObject,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): Array<oas31.ParameterObject | oas31.ReferenceObject> => {
   if (!zodObjectType) {
     return [];
@@ -112,7 +125,14 @@ const createParameters = (
   const zodObject = getZodObject(zodObjectType, 'input').shape as ZodRawShape;
 
   return Object.entries(zodObject).map(([key, zodSchema]: [string, ZodType]) =>
-    createParamOrRef(zodSchema, components, [...subpath, key], type, key),
+    createParamOrRef(
+      zodSchema,
+      components,
+      [...subpath, key],
+      documentOptions,
+      type,
+      key,
+    ),
   );
 };
 
@@ -120,32 +140,39 @@ const createRequestParams = (
   requestParams: ZodOpenApiParameters | undefined,
   components: ComponentsObject,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): NonNullable<oas31.OperationObject['parameters']> => {
   if (!requestParams) {
     return [];
   }
 
-  const pathParams = createParameters('path', requestParams.path, components, [
-    ...subpath,
+  const pathParams = createParameters(
     'path',
-  ]);
+    requestParams.path,
+    components,
+    [...subpath, 'path'],
+    documentOptions,
+  );
   const queryParams = createParameters(
     'query',
     requestParams.query,
     components,
     [...subpath, 'query'],
+    documentOptions,
   );
   const cookieParams = createParameters(
     'cookie',
     requestParams.cookie,
     components,
     [...subpath, 'cookie'],
+    documentOptions,
   );
   const headerParams = createParameters(
     'header',
     requestParams.header,
     components,
     [...subpath, 'header'],
+    documentOptions,
   );
 
   return [...pathParams, ...queryParams, ...cookieParams, ...headerParams];
@@ -163,13 +190,16 @@ export const createManualParameters = (
     | undefined,
   components: ComponentsObject,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): Array<oas31.ParameterObject | oas31.ReferenceObject> =>
   parameters?.map((param, index) => {
     if (isAnyZodType(param)) {
-      return createParamOrRef(param, components, [
-        ...subpath,
-        `param index ${index}`,
-      ]);
+      return createParamOrRef(
+        param,
+        components,
+        [...subpath, `param index ${index}`],
+        documentOptions,
+      );
     }
     return param as oas31.ParameterObject | oas31.ReferenceObject;
   }) ?? [];
@@ -187,13 +217,20 @@ export const createParametersObject = (
   requestParams: ZodOpenApiParameters | undefined,
   components: ComponentsObject,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): Array<oas31.ParameterObject | oas31.ReferenceObject> | undefined => {
   const manualParameters = createManualParameters(
     parameters,
     components,
     subpath,
+    documentOptions,
+  );
+  const createdParams = createRequestParams(
+    requestParams,
+    components,
+    subpath,
+    documentOptions,
   );
-  const createdParams = createRequestParams(requestParams, components, subpath);
   const combinedParameters: oas31.OperationObject['parameters'] = [
     ...manualParameters,
     ...createdParams,
diff --git a/src/create/paths.ts b/src/create/paths.ts
index cf0f20f..55faf11 100644
--- a/src/create/paths.ts
+++ b/src/create/paths.ts
@@ -7,6 +7,7 @@ import {
 } from './components';
 import { createContent } from './content';
 import type {
+  CreateDocumentOptions,
   ZodOpenApiOperationObject,
   ZodOpenApiPathItemObject,
   ZodOpenApiPathsObject,
@@ -20,6 +21,7 @@ export const createRequestBody = (
   requestBodyObject: ZodOpenApiRequestBodyObject | undefined,
   components: ComponentsObject,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): oas31.ReferenceObject | oas31.RequestBodyObject | undefined => {
   if (!requestBodyObject) {
     return undefined;
@@ -36,10 +38,13 @@ export const createRequestBody = (
 
   const requestBody: oas31.RequestBodyObject = {
     ...requestBodyObject,
-    content: createContent(requestBodyObject.content, components, 'input', [
-      ...subpath,
-      'content',
-    ]),
+    content: createContent(
+      requestBodyObject.content,
+      components,
+      'input',
+      [...subpath, 'content'],
+      documentOptions,
+    ),
   };
 
   if (ref) {
@@ -60,6 +65,7 @@ const createOperation = (
   operationObject: ZodOpenApiOperationObject,
   components: ComponentsObject,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): oas31.OperationObject | undefined => {
   const { parameters, requestParams, requestBody, responses, ...rest } =
     operationObject;
@@ -69,24 +75,28 @@ const createOperation = (
     requestParams,
     components,
     [...subpath, 'parameters'],
+    documentOptions,
   );
 
   const maybeRequestBody = createRequestBody(
     operationObject.requestBody,
     components,
     [...subpath, 'request body'],
+    documentOptions,
   );
 
   const maybeResponses = createResponses(
     operationObject.responses,
     components,
     [...subpath, 'responses'],
+    documentOptions,
   );
 
   const maybeCallbacks = createCallbacks(
     operationObject.callbacks,
     components,
     [...subpath, 'callbacks'],
+    documentOptions,
   );
 
   return {
@@ -102,6 +112,7 @@ export const createPathItem = (
   pathObject: ZodOpenApiPathItemObject,
   components: ComponentsObject,
   path: string[],
+  documentOptions?: CreateDocumentOptions,
 ): oas31.PathItemObject =>
   Object.entries(pathObject).reduce<oas31.PathItemObject>(
     (acc, [key, value]) => {
@@ -123,6 +134,7 @@ export const createPathItem = (
           value as ZodOpenApiOperationObject,
           components,
           [...path, key],
+          documentOptions,
         );
         return acc;
       }
@@ -137,6 +149,7 @@ export const createPathItem = (
 export const createPaths = (
   pathsObject: ZodOpenApiPathsObject | undefined,
   components: ComponentsObject,
+  documentOptions?: CreateDocumentOptions,
 ): oas31.PathsObject | undefined => {
   if (!pathsObject) {
     return undefined;
@@ -148,7 +161,12 @@ export const createPaths = (
         acc[path] = pathItemObject;
         return acc;
       }
-      acc[path] = createPathItem(pathItemObject, components, [path]);
+      acc[path] = createPathItem(
+        pathItemObject,
+        components,
+        [path],
+        documentOptions,
+      );
       return acc;
     },
     {},
diff --git a/src/create/responses.ts b/src/create/responses.ts
index 05cf657..9486375 100644
--- a/src/create/responses.ts
+++ b/src/create/responses.ts
@@ -9,6 +9,7 @@ import {
 } from './components';
 import { createContent } from './content';
 import type {
+  CreateDocumentOptions,
   ZodOpenApiResponseObject,
   ZodOpenApiResponsesObject,
 } from './document';
@@ -23,6 +24,7 @@ export const createResponseHeaders = (
     | AnyZodObject
     | undefined,
   components: ComponentsObject,
+  documentOptions?: CreateDocumentOptions,
 ): oas31.ResponseObject['headers'] => {
   if (!responseHeaders) {
     return undefined;
@@ -32,7 +34,7 @@ export const createResponseHeaders = (
     return Object.entries(responseHeaders.shape as ZodRawShape).reduce<
       NonNullable<oas31.ResponseObject['headers']>
     >((acc, [key, zodSchema]: [string, ZodType]) => {
-      acc[key] = createHeaderOrRef(zodSchema, components);
+      acc[key] = createHeaderOrRef(zodSchema, components, documentOptions);
       return acc;
     }, {});
   }
@@ -43,6 +45,7 @@ export const createResponseHeaders = (
 export const createHeaderOrRef = (
   schema: ZodType,
   components: ComponentsObject,
+  documentOptions?: CreateDocumentOptions,
 ): oas31.BaseParameterObject | oas31.ReferenceObject => {
   const component = components.headers.get(schema);
   if (component && component.type === 'complete') {
@@ -52,7 +55,7 @@ export const createHeaderOrRef = (
   }
 
   // Optional Objects can return a reference object
-  const baseHeader = createBaseHeader(schema, components);
+  const baseHeader = createBaseHeader(schema, components, documentOptions);
   if ('$ref' in baseHeader) {
     throw new Error('Unexpected Error: received a reference object');
   }
@@ -76,6 +79,7 @@ export const createHeaderOrRef = (
 export const createBaseHeader = (
   schema: ZodType,
   components: ComponentsObject,
+  documentOptions?: CreateDocumentOptions,
 ): oas31.BaseParameterObject => {
   const { ref, ...rest } = schema._def.openapi?.header ?? {};
   const state: SchemaState = {
@@ -83,6 +87,7 @@ export const createBaseHeader = (
     type: 'output',
     path: [],
     visited: new Set(),
+    documentOptions,
   };
   const schemaObject = createSchema(schema, state, ['header']);
   const required = !isOptionalSchema(schema, state)?.optional;
@@ -100,6 +105,7 @@ export const createResponse = (
   responseObject: ZodOpenApiResponseObject | oas31.ReferenceObject,
   components: ComponentsObject,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): oas31.ResponseObject | oas31.ReferenceObject => {
   if ('$ref' in responseObject) {
     return responseObject;
@@ -112,16 +118,23 @@ export const createResponse = (
 
   const { content, headers, ref, ...rest } = responseObject;
 
-  const maybeHeaders = createResponseHeaders(headers, components);
+  const maybeHeaders = createResponseHeaders(
+    headers,
+    components,
+    documentOptions,
+  );
 
   const response: oas31.ResponseObject = {
     ...rest,
     ...(maybeHeaders && { headers: maybeHeaders }),
     ...(content && {
-      content: createContent(content, components, 'output', [
-        ...subpath,
-        'content',
-      ]),
+      content: createContent(
+        content,
+        components,
+        'output',
+        [...subpath, 'content'],
+        documentOptions,
+      ),
     }),
   };
 
@@ -145,6 +158,7 @@ export const createResponses = (
   responsesObject: ZodOpenApiResponsesObject,
   components: ComponentsObject,
   subpath: string[],
+  documentOptions?: CreateDocumentOptions,
 ): oas31.ResponsesObject =>
   Object.entries(responsesObject).reduce<oas31.ResponsesObject>(
     (
@@ -158,10 +172,12 @@ export const createResponses = (
         acc[statusCode] = responseObject;
         return acc;
       }
-      acc[statusCode] = createResponse(responseObject, components, [
-        ...subpath,
-        statusCode,
-      ]);
+      acc[statusCode] = createResponse(
+        responseObject,
+        components,
+        [...subpath, statusCode],
+        documentOptions,
+      );
       return acc;
     },
     {},
diff --git a/src/create/schema/index.ts b/src/create/schema/index.ts
index eed6c08..8e021a1 100644
--- a/src/create/schema/index.ts
+++ b/src/create/schema/index.ts
@@ -8,6 +8,7 @@ import {
   type SchemaComponent,
   createComponentSchemaRef,
 } from '../components';
+import type { CreateDocumentOptions } from '../document';
 
 import { enhanceWithMetadata } from './metadata';
 import { createSchemaSwitch } from './parsers';
@@ -20,6 +21,7 @@ export interface SchemaState {
   type: CreationType;
   path: string[];
   visited: Set<ZodType>;
+  documentOptions?: CreateDocumentOptions;
 }
 
 const isDescriptionEqual = (schema: Schema, zodSchema: ZodType): boolean =>
diff --git a/src/create/schema/parsers/date.ts b/src/create/schema/parsers/date.ts
index 00797f2..afde893 100644
--- a/src/create/schema/parsers/date.ts
+++ b/src/create/schema/parsers/date.ts
@@ -1,10 +1,13 @@
 import type { ZodDate } from 'zod';
 
-import type { Schema } from '..';
+import type { Schema, SchemaState } from '..';
 
-export const createDateSchema = (_zodDate: ZodDate): Schema => ({
+export const createDateSchema = (
+  _zodDate: ZodDate,
+  state: SchemaState,
+): Schema => ({
   type: 'schema',
-  schema: {
+  schema: state.documentOptions?.defaultDateSchema ?? {
     type: 'string',
   },
 });
diff --git a/src/create/schema/parsers/index.ts b/src/create/schema/parsers/index.ts
index 3ecba9f..e5f6c45 100644
--- a/src/create/schema/parsers/index.ts
+++ b/src/create/schema/parsers/index.ts
@@ -114,7 +114,7 @@ export const createSchemaSwitch = <
   }
 
   if (isZodType(zodSchema, 'ZodDate')) {
-    return createDateSchema(zodSchema);
+    return createDateSchema(zodSchema, state);
   }
 
   if (isZodType(zodSchema, 'ZodPipeline')) {


Test patch:
diff --git a/src/create/document.test.ts b/src/create/document.test.ts
index dc589ef..ae7d3b0 100644
--- a/src/create/document.test.ts
+++ b/src/create/document.test.ts
@@ -2,6 +2,7 @@ import '../entries/extend';
 import { type ZodType, z } from 'zod';
 
 import {
+  type CreateDocumentOptions,
   type ZodOpenApiCallbackObject,
   type ZodOpenApiObject,
   createDocument,
@@ -1386,4 +1387,244 @@ describe('createDocument', () => {
       }
     `);
   });
+
+  it('Supports defaultDateSchema option', () => {
+    const UserSchema = z.object({
+      id: z.string(),
+      timestamp: z.date(),
+    });
+
+    const documentOptions: CreateDocumentOptions = {
+      defaultDateSchema: {
+        type: 'string',
+        format: 'date-time',
+      },
+    };
+
+    const document = createDocument(
+      {
+        info: {
+          title: 'My API',
+          version: '1.0.0',
+        },
+        openapi: '3.1.0',
+        components: {
+          schemas: {
+            User: UserSchema,
+          },
+        },
+        paths: {
+          '/timestamp/:timestamp': {
+            post: {
+              parameters: [
+                z.date().openapi({
+                  param: {
+                    in: 'path',
+                    name: 'timestamp',
+                    required: true,
+                  },
+                }),
+              ],
+              requestBody: {
+                content: {
+                  'application/json': {
+                    schema: z.object({
+                      timestamp: z.date(),
+                    }),
+                  },
+                },
+              },
+              responses: {
+                '200': {
+                  description: '200 OK',
+                  headers: z.object({
+                    timeStamp: z.date(),
+                  }),
+                  content: {
+                    'application/json': {
+                      schema: z.object({
+                        timestamp: z.date(),
+                      }),
+                    },
+                  },
+                },
+              },
+              callbacks: {
+                onData: {
+                  '{$request.query.callbackUrl}/data': {
+                    post: {
+                      requestBody: {
+                        content: {
+                          'application/json': {
+                            schema: z.object({
+                              timestamp: z.date(),
+                            }),
+                          },
+                        },
+                      },
+                      responses: {
+                        '202': {
+                          description: '200 OK',
+                          content: {
+                            'application/json': {
+                              schema: z.object({
+                                timestamp: z.date(),
+                              }),
+                            },
+                          },
+                        },
+                      },
+                    },
+                  },
+                },
+              },
+            },
+          },
+        },
+      },
+      documentOptions,
+    );
+
+    expect(document).toMatchInlineSnapshot(`
+      {
+        "components": {
+          "schemas": {
+            "User": {
+              "properties": {
+                "id": {
+                  "type": "string",
+                },
+                "timestamp": {
+                  "format": "date-time",
+                  "type": "string",
+                },
+              },
+              "required": [
+                "id",
+                "timestamp",
+              ],
+              "type": "object",
+            },
+          },
+        },
+        "info": {
+          "title": "My API",
+          "version": "1.0.0",
+        },
+        "openapi": "3.1.0",
+        "paths": {
+          "/timestamp/:timestamp": {
+            "post": {
+              "callbacks": {
+                "onData": {
+                  "{$request.query.callbackUrl}/data": {
+                    "post": {
+                      "requestBody": {
+                        "content": {
+                          "application/json": {
+                            "schema": {
+                              "properties": {
+                                "timestamp": {
+                                  "format": "date-time",
+                                  "type": "string",
+                                },
+                              },
+                              "required": [
+                                "timestamp",
+                              ],
+                              "type": "object",
+                            },
+                          },
+                        },
+                      },
+                      "responses": {
+                        "202": {
+                          "content": {
+                            "application/json": {
+                              "schema": {
+                                "properties": {
+                                  "timestamp": {
+                                    "format": "date-time",
+                                    "type": "string",
+                                  },
+                                },
+                                "required": [
+                                  "timestamp",
+                                ],
+                                "type": "object",
+                              },
+                            },
+                          },
+                          "description": "200 OK",
+                        },
+                      },
+                    },
+                  },
+                },
+              },
+              "parameters": [
+                {
+                  "in": "path",
+                  "name": "timestamp",
+                  "required": true,
+                  "schema": {
+                    "format": "date-time",
+                    "type": "string",
+                  },
+                },
+              ],
+              "requestBody": {
+                "content": {
+                  "application/json": {
+                    "schema": {
+                      "properties": {
+                        "timestamp": {
+                          "format": "date-time",
+                          "type": "string",
+                        },
+                      },
+                      "required": [
+                        "timestamp",
+                      ],
+                      "type": "object",
+                    },
+                  },
+                },
+              },
+              "responses": {
+                "200": {
+                  "content": {
+                    "application/json": {
+                      "schema": {
+                        "properties": {
+                          "timestamp": {
+                            "format": "date-time",
+                            "type": "string",
+                          },
+                        },
+                        "required": [
+                          "timestamp",
+                        ],
+                        "type": "object",
+                      },
+                    },
+                  },
+                  "description": "200 OK",
+                  "headers": {
+                    "timeStamp": {
+                      "required": true,
+                      "schema": {
+                        "format": "date-time",
+                        "type": "string",
+                      },
+                    },
+                  },
+                },
+              },
+            },
+          },
+        },
+      }
+    `);
+  });
 });
diff --git a/src/create/schema/parsers/date.test.ts b/src/create/schema/parsers/date.test.ts
index 6b6f023..4aaff47 100644
--- a/src/create/schema/parsers/date.test.ts
+++ b/src/create/schema/parsers/date.test.ts
@@ -2,6 +2,8 @@ import '../../../entries/extend';
 import { z } from 'zod';
 
 import type { Schema } from '..';
+import { createOutputState } from '../../../testing/state';
+import type { CreateDocumentOptions } from '../../document';
 
 import { createDateSchema } from './date';
 
@@ -15,7 +17,53 @@ describe('createDateSchema', () => {
     };
     const schema = z.date();
 
-    const result = createDateSchema(schema);
+    const result = createDateSchema(schema, createOutputState());
+
+    expect(result).toEqual(expected);
+  });
+
+  it('sets a custom format', () => {
+    const expected: Schema = {
+      type: 'schema',
+      schema: {
+        type: 'string',
+        format: 'date-time',
+      },
+    };
+    const schema = z.date();
+    const documentOptions: CreateDocumentOptions = {
+      defaultDateSchema: {
+        type: 'string',
+        format: 'date-time',
+      },
+    };
+
+    const result = createDateSchema(
+      schema,
+      createOutputState(undefined, documentOptions),
+    );
+
+    expect(result).toEqual(expected);
+  });
+
+  it('sets a custom type', () => {
+    const expected: Schema = {
+      type: 'schema',
+      schema: {
+        type: 'number',
+      },
+    };
+    const schema = z.date();
+    const documentOptions: CreateDocumentOptions = {
+      defaultDateSchema: {
+        type: 'number',
+      },
+    };
+
+    const result = createDateSchema(
+      schema,
+      createOutputState(undefined, documentOptions),
+    );
 
     expect(result).toEqual(expected);
   });
diff --git a/src/testing/state.ts b/src/testing/state.ts
index dbee859..68184b8 100644
--- a/src/testing/state.ts
+++ b/src/testing/state.ts
@@ -1,14 +1,19 @@
 import { getDefaultComponents } from '../create/components';
-import type { ZodOpenApiComponentsObject } from '../create/document';
+import type {
+  CreateDocumentOptions,
+  ZodOpenApiComponentsObject,
+} from '../create/document';
 import type { SchemaState } from '../create/schema';
 
 export const createOutputState = (
   componentsObject?: ZodOpenApiComponentsObject,
+  documentOptions?: CreateDocumentOptions,
 ): SchemaState => ({
   components: getDefaultComponents(componentsObject),
   type: 'output',
   path: [],
   visited: new Set(),
+  documentOptions,
 });
 
 export const createInputState = (