Subject: bug#26151: date-year-day screws up leap days prior to AD 1

From: Zefram <[email-masked]>
Date: Sat, 18 Mar 2017 01:10:58 +0000

In SRFI-19, the date-year-day function is meant to return the ordinal
day of the year for a date structure.  This value is properly 1 for the
first day of each calendar year, and on all other days 1 greater than
the value for the preceding day.  But the implementation occasionally
has it repeat a value:

scheme@(guile-user)> (use-modules (srfi srfi-19))
scheme@(guile-user)> (date-year-day (julian-day->date 1719657 0))
$1 = 59
scheme@(guile-user)> (date-year-day (julian-day->date 1719658 0))
$2 = 60
scheme@(guile-user)> (date-year-day (julian-day->date 1719659 0))
$3 = 60

and occasionally has it skip a value:

scheme@(guile-user)> (date-year-day (julian-day->date 1720023 0))
$4 = 59
scheme@(guile-user)> (date-year-day (julian-day->date 1720024 0))
$5 = 61

These errors happen around the end of February in years preceding AD 1.
In each leap year a value is repeated (ordinal values 1 too low from
March to December), and in each year immediately following a leap year
a value is skipped (ordinal values 1 too high from March to December).
Looking at the code, the bug arises from confusion between astronomical
year numbering (which leap-year? expects to receive) and the bizarre
zero-skipping year numbering that the library uses in the date structure
(which date-year-day passes, via year-day, to leap-year?).

Since the subject's come up: that year numbering used in the date
structures is surprising, and I'm not sure quite what to make of it.
It matches AD year numbering for years AD 1 onwards, but then numbers AD
0 (1 BC) as -1, and numbers all earlier years in accordance with that.
It's almost a straight linear numbering of years, except that it skips
the number 0.  (At least you've documented it.)  This is not a convention
that I've seen in real use anywhere else, and that weird exception to
the linearity makes it a pain to use.  It's likely to cause bugs in
user code, along the lines of the library bug that I've reported above
and the previously-reported bug#21903.  However, I haven't reported the
year numbering per se as a bug, because SRFI-19 doesn't actually say
what numbering is to be used for the date-year slot.

If I had implemented SRFI-19 myself, without reference to existing
implementations, I would have implemented astronomical year numbering
(consistent AD year numbering, extending linearly in both directions),
as used in ISO 8601.  This is the most conventional year numbering,
and at a stretch one could read SRFI-19 as implying it, by using some AD
year numbering and not saying to deviate from that scheme.  But really the
standard is silent on the issue.  Since the signification of date-year is
an interoperability issue, this silence is a problem, and it is troubling
that you and I have reached different interpretations of the standard
on this point.

Where did you get the idea to use a non-linear year numbering?  What's
your opinion of SRFI-19's (lack of) text on this matter?  You should
consider the possibility of changing your implementation to use the
conventional astronomical year numbering in this slot.

-zefram