I needed a regular expression to correctly parse ISO 8601 format dates and times. The standard includes many alternative representations, but I was particularly concerned about the subset of ISO 8601 formats allowed in XML.
Edit 26 May 2009: If you want full ISO compliance, check out the expression Cameron Brooks lists in his comment below.
Paul Ward had posted a date parsing expression on the RegExLib site. I extended it a bit to handle times and time zones. I’m pretty sure they work, though it can be hard to tell sometimes. (See Jeff Atwood’s Now You Have Two Problems.)
ISO date
^(\d{4})\D?(0[1-9]|1[0-2])\D?([12]\d|0[1-9]|3[01])$
ISO time
^([01]\d|2[0-3])\D?([0-5]\d)\D?([0-5]\d)?\D?(\d{3})?$
ISO offset
^([zZ]|([\+-])([01]\d|2[0-3])\D?([0-5]\d)?)?$
ISO date and time
^(\d{4})\D?(0[1-9]|1[0-2])\D?([12]\d|0[1-9]|3[01])(\D?([01]\d|2[0-3])\D?([0-5]\d)\D?([0-5]\d)?\D?(\d{3})?)?$
ISO date, time, and offset (the works)
^(\d{4})\D?(0[1-9]|1[0-2])\D?([12]\d|0[1-9]|3[01])(\D?([01]\d|2[0-3])\D?([0-5]\d)\D?([0-5]\d)?\D?(\d{3})?([zZ]|([\+-])([01]\d|2[0-3])\D?([0-5]\d)?)?)?$
If you find it useful — or find a bug — let me know.
Edit 21 Jan 2008: Stan James sent us some enhancements to the validation routines. Here’s what he had to say:
I needed a RegExp that could detect ISO dates with varying precision. (e.g. “1945″, “1945-12″, “1945-12-01″, “1945-12-01T12:15″ etc..)
For future readers, here’s what I came up with:
Date only
^[0-9][0-9][0-9][0-9](-[0-1][0-9](-[0-3][0-9])?)?$Date and Time
^[0-9][0-9][0-9][0-9](-[0-1][0-9](-[0-3][0-9](T[0-9][0-9](:[0-9][0-9](:[0-9][0-9])?)?)?)?)?$
Thanks, Stan!
6 Comments
Bookmarks about Iso
[...] – bookmarked by 2 members originally found by VissyLinch09 on 2008-11-13 ISO Date Validation RegEx http://underground.infovark.com/2008/07/22/iso-date-validation-regex/ – bookmarked by 5 members [...]
Cameron Brooks
I was in the same situation as you (needing ISO 8601 validation). Your “works” regex is great, but needed a bit more fine tuning to be truly ISO 8601 compliant. Here are some strings it matches on that should not be matched on:
2009-05-19T14a39r
2009-05-19T14:3924
2009-0519
2009-05-1914:39
2009-05-19r14:39
2009-05-19 14a39a22
200912-01
And here are some valid ISO 8601 dates that it should match on but doesn’t:
2009
2009-12T12:34
2009123
2009-05
2009-123
2009-222
2009-001
2009-W01-1
2009-W51-1
2009-W511
2009W511
2009-05-19 14
2009-W21-2
2009-139
2007-04-05T24:00
(Note that 24:00 is a valid representation of midnight according to ISO 8601, so I changed that.) Obviously, this doesn’t include the duration or time interval aspects of ISO 8601 (I left those out because I didn’t need them).
This is the modified regex I came up with:
^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])-?[1-7]|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s](([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)?(\15([0-5]\d))?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$
I’d love to hear your input.
19 May 2009 09:05 pm
Dean
Quite right, Cameron. The false positives you identified are definite bugs in the regular expression I’d posted.
And the following three false negatives you provided are also bugs:
2009
2009-05
2007-04-05T24:00
The other false negatives you listed are indeed valid ISO 8601 date strings. But the W3C recommendation excludes the day-of-year and week-of-year notation from the XML standard.
http://www.w3.org/TR/NOTE-datetime
So your expression is much better for strict compliance with ISO 8601. For compliance with XML, we’ll need something a little different. But either way, it’s time to update this page!
26 May 2009 11:05 pm
Bryan
Cameron Brooks’ solution doesn’t seem to handle fractional sections, FWIW. Other than that it seems to work pretty well.
18 Dec 2009 01:12 pm
Cameron Brooks
Hey guys. You’re quite correct that my regex didn’t account for fractional time elements. At the time I wrote it I didn’t require it for my application, and I didn’t realize how many people used them for super-precise ISO times. I’ve updated my regex to account for this.
Here are some strings that should match as valid:
2010-02-18T16:23:48.5
2010-02-18T16:23:48,444
2010-02-18T16:23:48,3-06:00
2010-02-18T16:23.4
2010-02-18T16:23,25
2010-02-18T16:23.33+0600
2010-02-18T16.23334444
2010-02-18T16,2283
2009-05-19 143922.500
2009-05-19 1439,55
And here are some strings that should not match as valid:
2009-05-19 146922.500
2010-02-18T16.5:23.35:48
2010-02-18T16:23.35:48
2010-02-18T16:23.35:48.45
2009-05-19 14.5.44
2010-02-18T16:23.33.600
2010-02-18T16,25:23:48,444
Here’s the updated regex that I was able to come up with:
^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$
It still doesn’t account for the duration or time interval part of the ISO 8601 spec, so I guess that’ll have to come at a later date.
Lemme know if you find any bugs.
18 Feb 2010 09:02 pm
Andre
Hi Cameron,
That is a great regex. Have you ever complted the full ISO 8601 regex, with intervals, durations, repeat periods?
If you have, it would be very useful for a StratML Specification Schema.
Thank you.
Regards,
Andre
30 Jun 2011 08:06 pm (@Twitter)
Leave a Comment