1. Date.iso8601 does not correctly parse some ISO 8601 formats like ordinal dates or month-only dates.
2. The Date class does not support year-only or year/month granularity.
In response to the first, the documentation for Date.iso8601 (http://ruby-doc.org/stdlib-1.9.3/libdoc/date/rdoc/Date.html#...) says:
"Creates a new Date object by parsing from a string according to some typical ISO 8601 formats."
Not "all ISO 8601 formats," "some typical ISO 8601 formats." While supporting more formats is obviously desirable, the method never claimed to be a complete ISO 8601 implementation. It would be nicer if it were, but would also take more work and it appears that 100% spec support was neither prioritized nor promised.
I believe the second complaint is less justified. Asking a single class (Date) to support multiple granularities opens up a lot of semantic conundrums that have no obvious resolution. What should this return?
Date.iso8601("2012-01") < Date.iso8601("2012-01-05")
If one is truly month granularity and one is day granularity, then the two aren't directly comparable. It would make more sense to me to have the month granularity representation be a separate class altogether (YearMonth?) with easy and well-defined conversions between the two.This case seems like an outright violation, however. If the standard says that ####-## is a year-month date with month granularity, and you interpret it as an ordinal date, then that's a clear violation. It means that others communicating with you won't just get an error, they will get the wrong answer, which is much worse.
PS I did my undergrad thesis on Ruby; I love the language. But now that I have a job where people read my code more often than it's written, I understand why things like clear semantics matter.
And why method names should be precise since they lead developers to assume behavior. Didn't your english teacher tell you a poem's title means something? So do method names. "iso8601" implies some meaningful relationship to ISO 8601, but the only relationship here is that the coders of this method were thinking hard about ISO 8601 when they wrote it.
Which I'll probably have to write. ;)
I think you’ll find a lot of APIs (or formats) claiming to support an “ISO 8601 date” when in fact they mean a date of the form “YYYY-MM-DD” — it’s a common misunderstanding, but I think better that, than actually allowing the full range of dates allowed by the actual ISO 8601 standard :)
However, I strongly agree that ranges of time are a very useful concept, and I spent a lot of time implementing Range Types[1] in postgresql for that reason. I think Ruby should have both ranges of time and points of time (and ideally work with the SQL counterparts seamlessly).
[1] http://www.postgresql.org/docs/9.2/static/rangetypes.html
2) Just because you didn't come in contact with ordinal dates doesn't mean others don't need it.
3) The article has a link to https://en.wikipedia.org/wiki/Ordinal_date. The wiki page doesn't have any specific use cases but just use your imagination.
It's not perfect, but no implementation will ever be imho.
Parsing it incorrectly is bad news.
I don't know the standard, but either Wikipedia is wrong or the Date implementation is sorely lacking.
I've been reading the source code of one ISO 8601 implementation in JavaScript and writing my own in Java. Looks like I'll have to fix the Ruby one too.
Given that it's used by, oh, HTML and XML, not properly implementing ISO 8601 is really no big deal.</sarcasm>
Tom Morris is right, they all suck when it comes to ISO-8601 support.
$ re.pl
>> use aliased 'DateTime::Format::ISO8601';
>> ISO8601->parse_datetime("2012-012");
2012-01-12T00:00:00
>> ISO8601->parse_datetime("2012-366");
2012-12-31T00:00:00
>> ISO8601->parse_datetime("2012-12");
2012-12-01T00:00:00
>> ISO8601->parse_datetime("2012");
2012-01-01T00:00:00
And if it isn't then there is also Date::ISO8601 [1] which is written by Zefram [2] who is renowned for being a Date/Time nut [3] :)1 - https://metacpan.org/module/Date::ISO8601
> If you aren’t doing ordinal dates, you aren’t doing ISO 8601.
It seems ruby1.9 does implement ordinal dates just fine:
irb(main):002:0> Date.iso8601("2012-012")
=> #<Date: 2012-01-12 ((2455939j,0s,0n),+0s,2299161j)>
irb(main):005:0> Date.iso8601("2012-366")
=> #<Date: 2012-12-31 ((2456293j,0s,0n),+0s,2299161j)>
What it does not implement is the "YYYY-MM" format: irb(main):010:0> Date.iso8601("2012-12")
=> #<Date: 2012-01-12 ((2455939j,0s,0n),+0s,2299161j)>http://tools.ietf.org/html/rfc3339
Basically, RFC3339 is ISO8601 cut down to the most straightforward implementation (YYYY-MM-DDTHH:MM:SS), without the "Ordinal Date" variant that is at issue here.
If I understand correctly, the complaint is that: ISO 8601 defines ####-## to be a year and month only, and it should have the granularity of a month; but Ruby treats it as an ordinal date.
It seems like it could be said much more clearly with an example:
irb(main):011:0> Date.iso8601("2012-12")
=> #<Date: 2012-01-12 ((2455939j,0s,0n),+0s,2299161j)>
It's treating ####-## as an ordinal date, when the standard says that it's a month-granularity date.Expect to see more of these headlines now Ruby 2.0.0 is out, as Rubyists start nudging users over by painting v 1.9 as defective. Good way to avoid the Python 3 and Perl 6 conundrums I suppose!