const regex = /^(?!-00:00)(?=^(?:Z|[\+\-](?:0[0-9]|1[012]):00|\+0[34569]:30|\+10:30|-03:30|-09:30|\+13:00|\+14:00|\+05:45|\+08:45|\+12:45))^((Z)|([\+\-])(\d\d):(\d\d))$/gm;
// Alternative syntax using RegExp constructor
// const regex = new RegExp('^(?!-00:00)(?=^(?:Z|[\\+\\-](?:0[0-9]|1[012]):00|\\+0[34569]:30|\\+10:30|-03:30|-09:30|\\+13:00|\\+14:00|\\+05:45|\\+08:45|\\+12:45))^((Z)|([\\+\\-])(\\d\\d):(\\d\\d))$', 'gm')
const str = `// Time Zone UTC Offsets in actual use for ISO 8601 / RFC 3339 (Museum of Bad Data)
// Accept: UTC indicator
Z
// Accept: Valid +xx:00
+00:00
+01:00
+02:00
+03:00
+04:00
+05:00
+06:00
+07:00
+08:00
+09:00
+10:00
+11:00
+12:00
+13:00
+14:00
// Accept: Valid -xx:00
-01:00
-02:00
-03:00
-04:00
-05:00
-06:00
-07:00
-08:00
-09:00
-10:00
-11:00
-12:00
// Accept: Valid +xx:30
+03:30
+04:30
+05:30
+06:30
+09:30
+10:30
// Accept: Valid +xx:45
+05:45
+08:45
+12:45
// Accept: Valid -xx:30
-03:30
-09:30
// Accept: Valid: 30 offsets
+03:30
+04:30
+05:30
+06:30
+09:30
+10:30
-03:30
-09:30
// Accept: Valid :45 offsets
+05:45
+08:45
+12:45
// Reject: valid RFC 3339, invalid ISO 8601
-00:00
// Reject: no such UTC offset in use
-13:00
-14:00
+00:01
+00:03
+00:99
+20:00
+0:00
// Reject: no such UTC offset in use
+01:30
+07:30
+08:30
+02:30
+11:30
+12:30
+13:30
+14:30
-01:30
-02:30
-04:30
-05:30
-06:30
-07:30
-08:30
-10:30
-11:30
-12:30
-13:30
-14:30
// Reject: Unused :45 offsets
+01:45
+02:45
+03:45
+04:45
+06:45
+07:45
+09:45
+10:45
+11:45
+13:45
+14:45
-01:45
-02:45
-03:45
-04:45
-05:45
-06:45
-07:45
-08:45
-09:45
-10:45
-11:45
-12:45
-13:45
-14:45
+01:15
+02:15
+03:15
+04:15
+05:15
+06:15
+07:15
+08:15
+09:15
+10:15
+11:15
+12:15
+13:15
+14:15
-01:15
-02:15
-03:15
-04:15
-05:15
-06:15
-07:15
-08:15
-09:15
-10:15
-11:15
-12:15
-13:15
-14:15
// Reject: Z stands alone
Z00:00
Z00
Z0
// Reject: hyphen required
0100
+0100
-0100
// Reject: colon required
+0100
// Reject: No extra characters
2001-02-03T04:05:06.007+0800
+08:00
+08:00
\`\`\`
### Expanded Pattern:
\`\`\`
^(?!-00:00)(?=^(?:Z|[\\+\\-](?:0[0-9]|1[012]):00|\\+0[34569]:30|\\+10:30|-03:30|-09:30|\\+13:00|\\+14:00|\\+05:45|\\+08:45|\\+12:45))^((Z)|([\\+\\-])(\\d\\d):(\\d\\d))\$
\`\`\`
\`\`\`
^ # use zero-width assertions to capture all the special cases:
(?!-00:00) # not -00:00
(?=^(?:
Z # Z alone works,
|[\\+\\-](?:0[0-9]|1[012]):00 # and all other +/- xx:00s,
|\\+0[34569]:30|\\+10:30|-03:30|-09:30 # the +/- xx:30s.
|\\+13:00|\\+14:00|\\+05:45|\\+08:45|\\+12:45 # and these special cases
)) # Now that we've forced only positive matches, let's capture the pieces:
^( # G1: the whole offset
(Z) | # G2: UTC indicator or nil
([\\+\\-]) # G3: +/- direction
(\\d\\d) # G4: "hours" part of offset
:
(\\d\\d) # G5: "minutes" part of offset
)\$
\`\`\`
`;
// Reset `lastIndex` if this regex is defined globally
// regex.lastIndex = 0;
let m;
while ((m = regex.exec(str)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(`Found match, group ${groupIndex}: ${match}`);
});
}
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for JavaScript, please visit: https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions