Utilo

ISO 8601 Datetime Regular Expression – Free, Online, Private

Matches a datetime with a T, seconds, an optional fraction, and a Z or a numeric offset.

Tester
Sample
Matches (2)
  • 2026-10-17T09:00:00Z
  • 2026-10-17T09:00:00.5+01:00

The pattern

2026-10-17T09:00:00Z matches. A fractional second and a numeric offset match. A space instead of T does not. A time without seconds does not. The pattern is deliberately stricter than 'anything ISO-ish'. It is the shape produced by toISOString in JavaScript and by many APIs. It does not check that the month and the day exist. Pair it with the date pattern's caveats: 2026-02-31T00:00:00Z matches the shape.

The source is ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$. The flags on this page are m. i means case-insensitive. m means ^ and $ match at line breaks, which is how the sample can show several candidates. g is not set. The tester finds non-overlapping matches, and without g a pattern with no anchor still reports the matches it walks. The box under the title is a tester with this pattern and the sample already filled in. Edit either one. Nothing you type is uploaded. The same tester, without a preset, is the regex tool.

How to read it

The date is four digits, hyphen, two, hyphen, two. T is literal and uppercase. The time is HH:MM:SS with two digits each. (?:\.\d+)? is an optional fraction of any length. (?:Z|[+-]\d{2}:\d{2}) is either Z or an offset such as +01:00 or -05:30. The offset requires a colon. +0100 without a colon does not match. Anchors and m test the sample line by line. The Z is case-sensitive. A lowercase z fails.

What it will not do

The hour is not limited to 23 by this pattern. \d{2} allows 99. Use the time pattern's hour branch if you want that tightness, and accept a longer expression. Week dates, ordinal dates, and durations are not matched. A trailing zone name such as America/New_York is not an ISO offset and does not match. The pattern does not convert the instant to UTC. It only recognizes the text. The cron pages on this site print next runs as ISO instants in Z form, which this pattern accepts.

A match is not a parsed value. An email pattern does not send mail, a UUID pattern does not allocate an id, and a password pattern does not store a password. When the next step needs a real parser, use one: the URL constructor, a date library, a semver library, or the converters on this site. The expression is the part you can see.

JavaScript, Python, and Go

The JavaScript snippet uses the RegExp constructor so the source does not have to be escaped for a literal slash. The Python snippet uses a normal string with the same escapes JSON would emit, which keeps \d as a regex digit class. Go's snippet uses a raw string. If the pattern contains a lookahead, the Go snippet says so and does not call MustCompile, because RE2 would reject it at runtime.

JavaScriptconst re = new RegExp("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$", "m");
const found = text.match(re);
console.log(found ? found[0] : "no match");
Pythonimport re

pattern = re.compile("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$", re.MULTILINE)
found = pattern.search(text)
print(found.group(0) if found else "no match")
Gopackage main

import (
	"fmt"
	"regexp"
)

func main() {
	text := ""
	re := regexp.MustCompile(`(?m)^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$`)
	fmt.Println(re.FindString(text))
}

Frequently asked questions

Does a space instead of T match?

No. The separator is a literal T. Some profiles allow a space. This one does not.

Is a fractional second required?

No. It is optional. If it is present, it needs at least one digit.

Does +0100 match?

No. The offset includes a colon: +01:00.

Are impossible dates rejected?

No. The pattern checks the shape, not the calendar. 2026-02-31 matches.