v4: Allow HH:MM format in `z.iso.datetime()` and `z.iso.time()`
Ports https://github.com/colinhacks/zod/pull/4315 to v4
Closes #4468
Summary by CodeRabbit
-
Documentation
- Clarified and expanded documentation for ISO datetime and time string validation, including new examples for accepted formats and precision constraints.
-
Tests
- Updated and expanded test cases to cover ISO datetime and time strings with and without seconds, including new valid and invalid scenarios.
- Adjusted test patterns and template literals to align with updated validation logic.
-
Style
- Reformatted function signatures and parameter declarations for improved readability (no functional changes).
Walkthrough
The changes update documentation, regex patterns, and tests to ensure that ISO 8601 datetime and time strings without seconds (e.g., "2020-01-01T00:00" and "23:59") are accepted by relevant validators when no precision is set. Test cases and regex logic were adjusted to reflect this behavior.
Changes
| File(s) | Change Summary |
|---|---|
packages/docs/content/api.mdx |
Updated documentation and examples to clarify acceptance of ISO datetime/time strings without seconds. |
packages/zod/src/v4/classic/tests/json-schema.test.ts,.../template-literal.test.ts |
Updated test snapshots and regex patterns to make seconds optional in ISO datetime/time patterns. |
packages/zod/src/v4/classic/tests/string.test.ts |
Switched to z.iso for date/time parsing, added tests for truncated datetime/time formats, updated failures. |
packages/zod/src/v4/core/regexes.ts |
Refactored regex construction for time patterns to make seconds optional when no precision is set. |
Sequence Diagram(s)
sequenceDiagram
participant User
participant HTMLInput
participant ZodValidator
User->>HTMLInput: Enter "2025-05-21T12:00" (no seconds)
HTMLInput->>ZodValidator: Submit value
ZodValidator->>ZodValidator: Apply regex (seconds optional)
alt Valid ISO 8601 local datetime
ZodValidator-->>User: Accept input
else Invalid format
ZodValidator-->>User: Reject input
end
Assessment against linked issues
| Objective | Addressed | Explanation |
|---|---|---|
Accept ISO 8601 local datetime strings without seconds in z.iso.datetime({ local: true }) (#4468) |
✅ |
Possibly related PRs
- colinhacks/zod#4315: Updates documentation and examples to clarify acceptance of ISO datetime/time strings without seconds, similar to these changes.
Poem
No seconds? No stress—just hours and minutes,
Now Zod's regex lets your input fit in it!
Docs and tests in harmony,
Parsing time more flexibly,
So "2025-05-21T12:00" shines—
Cheers to code that reads between the lines! ⏰
[!NOTE]
⚡️ AI Code Reviews for VS Code, Cursor, Windsurf
CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback. Learn more here.
📜 Recent review details
Configuration used: CodeRabbit UI Review profile: ASSERTIVE Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between 592de8de6e9c1f1d41aaa68e2c8ba57adced6507 and 38fb8c7140cf7d61a57f27cb0074d9c51dc25162.
📒 Files selected for processing (5)
-
packages/docs/content/api.mdx(4 hunks) -
packages/zod/src/v4/classic/tests/json-schema.test.ts(4 hunks) -
packages/zod/src/v4/classic/tests/string.test.ts(4 hunks) -
packages/zod/src/v4/classic/tests/template-literal.test.ts(1 hunks) -
packages/zod/src/v4/core/regexes.ts(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/zod/src/v4/classic/tests/string.test.ts (1)
packages/zod/src/v4/core/regexes.ts (3)
datetime(101-113)date(82-82)time(96-98)
🔇 Additional comments (26)
packages/zod/src/v4/core/regexes.ts (3)
84-94: Nice refactor on the time regex logic! 🎯Love how you've separated the seconds regex construction and made the quantifier conditional. The logic is clean and intuitive - when precision is specified, seconds are required (
+), otherwise they're optional (?). This perfectly enables the HH:MM format support while keeping existing behavior intact.The step-by-step construction makes it much easier to understand what's happening compared to the previous inline approach.
96-98: Clean formatting update.Nice touch making the function signature more readable with the multi-line parameter formatting.
115-118: Consistent formatting improvement.Good call on the multi-line parameter object - makes it way more readable, especially when parameters have longer names.
packages/zod/src/v4/classic/tests/template-literal.test.ts (1)
554-555: Snapshot update looks spot on! ✅The updated regex pattern correctly reflects the optional seconds behavior -
(:[0-5]\\d(\\.\\d+)?)?nicely captures the "seconds are optional but if present, fractional seconds are also optional" logic.packages/zod/src/v4/classic/tests/json-schema.test.ts (4)
65-65: JSON Schema snapshot updated correctly! 🎉The pattern now properly includes the optional seconds group while maintaining support for fractional seconds when they're present. Consistent with the core regex changes.
81-81: Time format snapshot also updated correctly.Nice consistency - the time format now supports HH:MM just like the datetime format. Same clean optional seconds pattern.
284-284: Consistent datetime pattern across test sections.Good to see the same pattern update applied consistently in the string formats section too.
301-301: Complete and consistent snapshot updates! 💯Love seeing all the related snapshots updated consistently. The pattern changes are identical across all occurrences, which shows careful attention to detail in updating all the affected test cases.
packages/docs/content/api.mdx (6)
342-342: Awesome addition: optional seconds in default datetime
This new example clearly shows thatz.iso.datetime()accepts"YYYY-MM-DDTHH:MM"when precision isn’t set.
359-359: Great callout: omitted seconds in offset mode
Nice to see"2020-01-01T00:00Z"listed under the offsets example to illustrate seconds can be omitted there too.
366-366: Solid example for local mode
Love how you added the example showing"2020-01-01T00:00"passes whenlocal: true.
376-376: Precision enforcement example looks good
This makes it clear that missing seconds are invalid when aprecisionoption is set.
397-397: z.iso.time doc updated nicely
The description now accurately indicates support forHH:MMorHH:MM:SS[.s+].
402-402: Nice demonstration for time parsing
Good to includetime.parse("00:00")to show theHH:MMformat is valid.packages/zod/src/v4/classic/tests/string.test.ts (12)
717-717: LGTM! Clean migration to the new v4 API.Nice and clean update from the old
z.string().datetime()to the newz.iso.datetime()namespace. This aligns perfectly with the v4 migration goals.
723-723: Good addition for testing HH:MM format support.This test case properly validates that datetime strings without seconds (like "2022-10-13T09:52Z") are now accepted, which is exactly what this PR aims to achieve.
729-729: Smart edge case testing!This failure test correctly ensures that malformed datetime strings like "2020-10-14T17:42.123+00:00" (where fractional notation is incorrectly applied to minutes) are properly rejected. Good defensive testing.
731-731: Consistent API migration and logical test case.The migration to
z.iso.datetime({ precision: 0 })is spot on, and adding the HH:MM test case makes total sense here since precision: 0 means no fractional seconds are expected anyway.Also applies to: 734-734
740-740: Correct behavior for precision requirements.Good API migration and the failure test makes perfect sense - when
precision: 3is specified, you need exactly 3 fractional second digits, so HH:MM format (which has no seconds at all) should definitely fail.Also applies to: 747-747
749-749: Nice coverage for offset scenarios.Clean API migration and the new test case "2020-10-14T17:42+0315" nicely demonstrates that HH:MM format works properly with timezone offsets. Good comprehensive testing.
Also applies to: 757-757
762-762: Perfect combination of features tested.The API migration is clean and the test case "2020-10-14T17:42+0000" perfectly demonstrates the combination of HH:MM format with timezone offset and no fractional seconds. All the pieces fit together nicely.
Also applies to: 767-767
775-775: Consistent precision logic maintained.Good API migration and the failure test is spot on - even with offset support, when
precision: 4is specified, HH:MM format should fail since it lacks the required fractional seconds. Logical consistency maintained.Also applies to: 783-783
787-787: Clean date schema migration.Straightforward and correct migration from
z.string().date()toz.iso.date(). Nice and consistent with the other API updates.
841-841: Core feature implemented correctly!Perfect API migration and the test case "23:59" is exactly what this PR is all about - allowing HH:MM time format without seconds. This is the key functionality being added.
Also applies to: 849-849
862-862: Good validation boundary testing.Smart test case with "24:60" - even though HH:MM format is now allowed, invalid hour/minute values should still be properly rejected. Good defensive testing.
864-864: Consistent precision logic for time schemas.Clean API migration and the failure test correctly enforces that HH:MM format should fail when
precision: 2is specified, since fractional seconds are required. The logic is consistent with datetime precision handling.Also applies to: 875-875
✨ Finishing Touches
- [ ] 📝 Generate Docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
🪧 Tips
Chat
There are 3 ways to chat with CodeRabbit:
- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
-
I pushed a fix in commit <commit_id>, please review it. -
Explain this complex logic. -
Open a follow-up GitHub issue for this discussion.
-
- Files and specific lines of code (under the "Files changed" tab): Tag
@coderabbitaiin a new review comment at the desired location with your query. Examples:-
@coderabbitai explain this code block. -
@coderabbitai modularize this function.
-
- PR comments: Tag
@coderabbitaiin a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:-
@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase. -
@coderabbitai read src/utils.ts and explain its main purpose. -
@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format. -
@coderabbitai help me debug CodeRabbit configuration file.
-
Support
Need help? Create a ticket on our support page for assistance with any issues or questions.
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.
CodeRabbit Commands (Invoked using PR comments)
-
@coderabbitai pauseto pause the reviews on a PR. -
@coderabbitai resumeto resume the paused reviews. -
@coderabbitai reviewto trigger an incremental review. This is useful when automatic reviews are disabled for the repository. -
@coderabbitai full reviewto do a full review from scratch and review all the files again. -
@coderabbitai summaryto regenerate the summary of the PR. -
@coderabbitai generate docstringsto generate docstrings for this PR. -
@coderabbitai generate sequence diagramto generate a sequence diagram of the changes in this PR. -
@coderabbitai resolveresolve all the CodeRabbit review comments. -
@coderabbitai configurationto show the current CodeRabbit configuration for the repository. -
@coderabbitai helpto get help.
Other keywords and placeholders
- Add
@coderabbitai ignoreanywhere in the PR description to prevent this PR from being reviewed. - Add
@coderabbitai summaryto generate the high-level summary at a specific location in the PR description. - Add
@coderabbitaianywhere in the PR title to generate the title automatically.
CodeRabbit Configuration File (.coderabbit.yaml)
- You can programmatically configure CodeRabbit by adding a
.coderabbit.yamlfile to the root of your repository. - Please see the configuration documentation for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation:
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
Documentation and Community
- Visit our Documentation for detailed information on how to use CodeRabbit.
- Join our Discord Community to get help, request features, and share feedback.
- Follow us on X/Twitter for updates and announcements.
Thanks for the PR. I've been pondering this and merged some changes in https://github.com/colinhacks/zod/pull/4680 including a fix for this. Landed in [email protected].