Time Library Date Normalisation and Arithmetic
andrew at pimlott.net
Mon Jul 11 13:40:07 EDT 2005
On Mon, Jul 11, 2005 at 02:53:25AM -0700, Ashley Yakeley wrote:
> A normalising construction function is a good idea. But if we hide the
> GregorianDay constructor, two of your use cases become slightly harder:
> "How do I truncate a date to the first of the month?"
> "How do I truncate a date to the first day of the year it occurred in?"
I dislike the "let the user muck with the data structure and expect the
library to figure out what he meant" style. For one thing, it means
that at some point, there is an intermediate value whose semantics are
unclear. (Can you document what will happen if it is passed to all
functions?) For another, the reader of the code has to look ahead to
see what kind of normalization is eventually done. There are enough
ambiguous cases in date handling that I would prefer to be explicit
As a date API user, I think that those use cases become more clear in
the style that Brian suggested.
d2 = d1 `changeDayOfMonth` 1
d2 = d1 `changeDayOfYear` 1
Now, I've only followed this thread loosely (these examples may be
inconsistent with the proposed API, sorry), and I realize that this
style has disadvantages: it may be tedious or slow if you have to
combine many operations. But I fear the alternative is a mess of
difficult-to-document-and-remember normalization rules for invalid
> This is actually quite appealing, though it's a rather radical change.
> The answers to the use-cases above become
> d' = makeGregorianTruncate (gregorianYear d) (gregorianMonth d) 1
> d' = makeGregorianTruncate (gregorianYear d) 1 1
Nobody's going to like that. :-)
> Is it better to have simple functions for each combination (your scheme)
> or selector functions (my original scheme)?
I tend to like the former, because the ambiguous cases for the different
units are different, and can be documented separately. Easier for the
programmer to understand what he's asking for.
More information about the Libraries