haskell / time

A time library
http://hackage.haskell.org/package/time
Other
120 stars 80 forks source link

Should `iso8601DateFormat` use `%0Y`? #111

Closed Gabriella439 closed 5 years ago

Gabriella439 commented 5 years ago

The context for this question is that our code was formatting a (malformed) date that is in the year 7 (due to data quality issues with the input as you might guess, which is a separate issue). So we formatted the date using Data.Time.Format.iso8601DateFormat which sets the date half of the format string to %Y-%m-%d. However, %Y does not pad with zeroes, which led to the format string beginning with the year "7-…" instead of "0007-…". This caused issues for interop with date parsing libraries written in other languages.

We have a very easy fix on our end, which is to not use Data.Time.Format.iso8601DateFormat and instead construct our own format string using %0Y, but I was still curious if the iso8601DateFormat utility should contain the same change or not to pad with zeroes. I saw the documentation which says that the format string is correct according to the wikipedia article on ISO 8601 dates, but I read the article and couldn't find anything conclusive either way.

So I tried to find the original specification and the closest thing I could find was:

... which provides a normative ABNF grammar for dates which, among other things, specifies that a year is always at least four digits:

year = positiveYear | negativeYear | "0000" ;

positiveYear = positiveDigit, digit, digit, digit 
    | "0", positiveDigit, digit, digit 
    | "00", positiveDigit, digit 
    | "000", positiveDigit ;

Anyway, I don't have strong opinions either way. The main reason I opened this issue is that I was curious which language implementation was correct. Should an ISO 8601 date parser require four digit years or not?

AshleyYakeley commented 5 years ago

Thanks. It looks like iso8601DateFormat is wrong and should be deprecated.

In the 1.9 release I introduced Data.Time.Format.ISO8601, which matches the formats in that standard. You should use iso8601Show and iso8601ParseM, which use the most commonly used formats. In particular, the year is padded to four digits.

Prelude Data.Time.Format.ISO8601 Data.Time> iso8601Show $ ModifiedJulianDay $ -645354
"0091-12-16"
Gabriella439 commented 5 years ago

Ah, thanks! Data.Time.Format.ISO8601 is exactly what I was looking for

AshleyYakeley commented 5 years ago

Fixed in master branch: iso8601DateFormat is deprecated.