<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Pelago :: web design &#38; development blog &#187; iso-8601</title>
	<atom:link href="http://www.pelagodesign.com/blog/tag/iso-8601/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.pelagodesign.com/blog</link>
	<description>Santa Barbara Web Design and Web Development Blog on the web world and other randoms</description>
	<lastBuildDate>Wed, 09 Mar 2011 16:31:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>ISO 8601 Date Validation That Doesn&#8217;t Suck</title>
		<link>http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/</link>
		<comments>http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/#comments</comments>
		<pubDate>Wed, 20 May 2009 16:38:25 +0000</pubDate>
		<dc:creator>Cameron</dc:creator>
				<category><![CDATA[Creative Engineering]]></category>
		<category><![CDATA[iso-8601]]></category>
		<category><![CDATA[regex]]></category>
		<category><![CDATA[regular expressions]]></category>
		<category><![CDATA[validation]]></category>

		<guid isPermaLink="false">http://www.pelagodesign.com/blog/?p=448</guid>
		<description><![CDATA[UPDATED February 19th, 2010: As BobM pointed out, the original solution to this problem didn&#8217;t account for fractional decimals. Originally I didn&#8217;t include them because Intervals didn&#8217;t require that level of precision, but apparently fractional decimals are quite common elsewhere. Because of that, I&#8217;ve updated this post, along with the regex, to include support for [...]]]></description>
			<content:encoded><![CDATA[<p><strong>UPDATED February 19th, 2010:</strong> <em>As <a href="#comment-6503" title="View BobM's comment">BobM</a> pointed out, the original solution to this problem didn&#8217;t account for fractional decimals. Originally I didn&#8217;t include them because Intervals didn&#8217;t require that level of precision, but apparently fractional decimals are quite common elsewhere. Because of that, I&#8217;ve updated this post, along with the regex, to include support for fractional decimals.</em></p>
<p>For the Intervals API, we&#8217;re wrestling with issues surrounding data input validation. This recently became interesting when the matter of date validation came up. Ordinarily, Intervals allows many, many different date formats, dependent on the locale that the customer is using (for example, Intervals may expect the date format &#8216;mm/dd/yyyy&#8217; for US customers, &#8216;dd.mm.yy&#8217; for a customer in Austria).</p>
<p>For our API developers, we wanted to use a common, universal format, one that would be easily compatible with our application and database layers. For that we selected ISO 8601, which is great in terms of widespread use, but not so great in terms of how complicated its specifications are.</p>
<p>Generally, ISO 8601 looks something like &#8217;2009-05-20&#8242; for dates and &#8217;2009-05-20 12:30:30&#8242; for date/time combinations. These two examples encompass 98% of the user input we&#8217;re likely to encounter. But we wanted to make sure that if we told developers they could use ISO 8601 dates, our system would support it. <span id="more-448"></span>Unfortunately, there&#8217;s not a lot of code out there for the validation of ISO 8601 dates (especially regular expressions), and most of the stuff that <em>is</em> out there doesn&#8217;t encompass the entirety of the ISO 8601 spec.</p>
<p>Starting off, here are some dates that the validator <strong>should</strong> match (all these are valid ISO 8601 dates to the best of my knowledge):</p>
<p>2009-12T12:34<br />
2009<br />
2009-05-19<br />
2009-05-19<br />
20090519<br />
2009123<br />
2009-05<br />
2009-123<br />
2009-222<br />
2009-001<br />
2009-W01-1<br />
2009-W51-1<br />
2009-W511<br />
2009-W33<br />
2009W511<br />
2009-05-19<br />
2009-05-19 00:00<br />
2009-05-19 14<br />
2009-05-19 14:31<br />
2009-05-19 14:39:22<br />
2009-05-19T14:39Z<br />
2009-W21-2<br />
2009-W21-2T01:22<br />
2009-139<br />
2009-05-19 14:39:22-06:00<br />
2009-05-19 14:39:22+0600<br />
2009-05-19 14:39:22-01<br />
20090621T0545Z<br />
2007-04-06T00:00<br />
2007-04-05T24:00</p>
<p><em>Added Feb 19 2010:</em><br />
2010-02-18T16:23:48.5<br />
2010-02-18T16:23:48,444<br />
2010-02-18T16:23:48,3-06:00<br />
2010-02-18T16:23.4<br />
2010-02-18T16:23,25<br />
2010-02-18T16:23.33+0600<br />
2010-02-18T16.23334444<br />
2010-02-18T16,2283<br />
2009-05-19 143922.500<br />
2009-05-19 1439,55</p>
<p>And here are some of the strings that the validator <strong>should not</strong> match (ie. reject):</p>
<p>200905<br />
2009367<br />
2009-<br />
2007-04-05T24:50<br />
2009-000<br />
2009-M511<br />
2009M511<br />
2009-05-19T14a39r<br />
2009-05-19T14:3924<br />
2009-0519<br />
2009-05-1914:39<br />
2009-05-19 14:<br />
2009-05-19r14:39<br />
2009-05-19 14a39a22<br />
200912-01<br />
2009-05-19 14:39:22+06a00</p>
<p><em>Added Feb 19 2010:</em><br />
2009-05-19 146922.500<br />
2010-02-18T16.5:23.35:48<br />
2010-02-18T16:23.35:48<br />
2010-02-18T16:23.35:48.45<br />
2009-05-19 14.5.44<br />
2010-02-18T16:23.33.600<br />
2010-02-18T16,25:23:48,444</p>
<p>The code we came up with was the following:</p>
<p><em>Updated Feb 19 2010:</em><br />
<code>^([\+-]?\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)?)?)?)?$</code></p>
<p>I guess I should add the caveat that this code doesn&#8217;t support the time interval or duration part of the ISO 8601 spec, so I didn&#8217;t include it. And it only supports dates or date/times, since right now we don&#8217;t have to deal with time input (for the Intervals API, all time is input in decimal format, rather than ISO 8601). But it should support everything else. Please let me know if this works for you or doesn&#8217;t, of if you can fine tune it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>ISO Week and Year in PHP and PostgreSQL</title>
		<link>http://www.pelagodesign.com/blog/2008/01/10/iso-week-and-year-in-php-and-postgresql/</link>
		<comments>http://www.pelagodesign.com/blog/2008/01/10/iso-week-and-year-in-php-and-postgresql/#comments</comments>
		<pubDate>Thu, 10 Jan 2008 16:48:49 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[Creative Engineering]]></category>
		<category><![CDATA[iso-8601]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[postgresql]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://www.pelagodesign.com/blog/2008/01/10/iso-week-and-year-in-php-and-postgresql/</guid>
		<description><![CDATA[The new year always brings with it a few small things that go bump in the morning. 2008 was no different. Intervals started behaving oddly on New Year&#8217;s Eve morning — the default timesheet was a year behind schedule. What happened? In our PHP code, we are using the ISO-8601 week number of year, as [...]]]></description>
			<content:encoded><![CDATA[<p>The new year always brings with it a few small things that go bump in the morning. 2008 was no different. <a href="http://www.myintervals.com/">Intervals</a> started behaving oddly on New Year&#8217;s Eve morning — the default timesheet was a year behind schedule. What happened?</p>
<p>In our PHP code, we are using the ISO-8601 week number of year, as specified on the <a href="http://php.net/date">PHP date function page</a>, but we weren&#8217;t using ISO-8601 for the year. The ISO-8601 week number specifies the last monday of a year as the first week of the new year, if that new year begins before thursday. Intervals thought it was the first year of 2007!</p>
<p>In PHP, the fix was as easy as converting all instances of date(&#8216;Y&#8217;) to date(&#8216;o&#8217;), according to <a href="http://php.net">php.net</a>:</p>
<blockquote><p>ISO-8601 year number. This has the same value as Y, except that if the ISO week number (W) belongs to the previous or next year, that year is used instead. (added in PHP 5.1.0)</p></blockquote>
<p>That fixed everything on the PHP side of things. But next we had to dig into the SQL queries and get them to use the ISO Year.</p>
<p>Snag.</p>
<p><a href="http://www.postgresql.org/">PostgreSQL 8.2.5</a> doesn&#8217;t support ISO Year in the Extract function. EXTRACT(ISOYEAR, timestamp) is being included in PostgreSQL 8.3, <a href="http://developer.postgresql.org/pgdocs/postgres/functions-datetime.html">as specified here in the RC1 documentation</a>. But PostgreSQL 8.3 hasn&#8217;t been released yet, and we needed to fix things immediately.</p>
<p>Our final PostgreSQL fix was to instead use the <a href="http://www.postgresql.org/docs/8.2/interactive/functions-formatting.html">TO_CHAR(timestamp, &#8216;IYYY&#8217;) function</a>. It&#8217;s not ideal to be using a string formatting function for data comparisons, because it slows down some of the queries. But we had to trade some performance to get things working properly again in the new year. <a href="http://www.postgresql.org/community/weeklynews/">As soon as the PostgreSQL developers release a stable version of 8.3</a>, we&#8217;ll change our queries back to using EXTRACT(ISOYEAR, timestamp). </p>
]]></content:encoded>
			<wfw:commentRss>http://www.pelagodesign.com/blog/2008/01/10/iso-week-and-year-in-php-and-postgresql/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

