Definitions of date arithmetic

Ken Pizzini ken at
Sat Oct 10 18:58:39 UTC 1998

On 9 Oct 1998 23:17:26 -0000, D. J. Bernstein <djb at> wrote:
>What is 1 month before 31 March? What is 1 month before 16 March? What
>is 1 month before 1 March?
>What is 1 month after 1 February? What is 1 month after 16 February?
>What is 1 month after 28 February?

Of the questions you ask, the only one which I find poorly defined
is "1 month before 31 March".  If I wanted, say, 30 days before any
of those dates I would have used d.tm_mday = -30 (or even just
direct arithmetic on a TIME_UTC xtime date).  (Of course, there
are many other poorly defined situations, I just don't think that
the other dates you ask about are problemmatical.)

>> Now the API itself needs a fair bit more thought than I've given it;
>Semantics first, please.

The basic plan is: add the (signed) values in the delta to the
corresponding fields in the base tm, using overflow rules appropriate
to the field.  Thus an underflow in tm_mon causes tm_year to decrement,
and an overflow in tm_mday causes an increment of tm_mon.

As to the ambigous cases, how about this revision to my off-the-cuff API:
    int add_tm(struct tm *value, struct tm delta, timezonet_t, int guess_flag);

If "guess_flag" is zero, then add_tm() shall fail if the request is
not well defined ("one month after March 31").  If guess_flag is
non-zero, then add_tm() shall force some plausible interpretation
(*) on the result (e.g., adjusting a tm_mon where tm_mday is in
{29,30,31} and the target month won't hold that value results in
tm_mday being forced to the maximum value for the target month).

(*) Yes, this needs to be much better defined.  I'm first
    interested in whether others think that the add_tm() function
    would be appropriate to add to the standard, assuming that it
    can be adequately defined.  I suspect that an appropriately
    weasle-worded description can be worked out that should satisfy
    most potential users of such a function most of the time, even
    though I sincerely doubt that there exists a single definition
    which will work for all possible application domains.

My main concern is: this is an often-desired function, as
ill-defined as it may be.  Using C89 the best one could do is to
use mktime() to do the normalization, but the mktime() interface
looses information which can be helpful to the implementation
in trying to disambibuate what the user was trying to request.
While in an ideal world we could tell our clients that their
business rules are ill-defined, as a practical matter we will
need to do our best to handle requests of the form "six months
from today".  Sometimes we are allowed to interpret this as
"180 days from today", sometimes we are required to add 6 to
tm_mon, and overflow into tm_year if need be, and what to do
if the tm_mday does not exist for that target month varies (but
typically for such business rules, we take the last day of the
target month for this situation).

I suppose that what would be even better is if there were some
reasonable way to directly expose the encoding of the calendar
(which the implementation needs in order to handle xtime_breakup(),
e.g.) so that an application can make use of it for its needs,
as I feel that per-application attempts to duplicate this
information tend to be quite error-prone.  I just can't think
of such an interface, and add_tm() is intended to provide the
main functionality that I think applications would want such
exposure for.

		--Ken Pizzini

More information about the tz mailing list