# strftime %y and negative years

Clive D.W. Feather clive at demon.net
Fri Aug 20 08:29:30 UTC 2004

```Paul Eggert said:
> Yes, that's correct: it's trying to produce the year modulo 100.
>
>> But the latest IEEE Std 1003.1 calls for...
>>
>> 	%y	Replaced by the last two digits of the year as a decimal
>>		number [00,99].
>
> Read literally, this would have undefined behavior for the years -9
> through 9 (since they don't have two digits), and would generate "10"
> for the year -10, and so forth, which obviously disagrees with the
> proposed "year modulo 100" semantics.

Ouch. This wording comes from ISO C, and we plain didn't think about that.

It looks like another DR is required.

Note, by the way, that strftime is only supposed to work when the relevant
fields are in their "normal range". No such range is given for tm_year.

> However, I just checked 3 implementations

It would be interesting to see what they do with %C as well:

%C  is  replaced by the year divided by 100 and truncated to
an integer, as a decimal number (00-99).

> year (i.e.,    glibc 2.2.5   OpenBSD 3.4   Solaris 9
> tm_year-1900)  (Debian                     patch 112874-29
>                2.2.5-11.5)                 (64-bit sparc)
> -101              99            -1           0/
> -100              00            00           00
>  -99              01           -99           '' (i.e., two apostrophes)
>  ...
>   -2              98            -2           0.
>   -1              99            -1           0/
>    0              00            00           00
>    1              01            01           ''
>  ...
>    9              09            09           '/
>   10              10            10           '0
>   11              11            11           ('
>  ...
>   99              99            99           0/

The glibc and OpenBSD behaviours appear to be using the % operator. This is
defined by:

the expression (a/b)*b + a%b shall equal a.

If b is positive (here, it's 100) and a is negative, there are two
possibilities in C90:

(1) a/b rounds towards zero (this is required in C99) and a%b is negative.
This is what OpenBSD appears to be doing, with a = tm_year - 1900.
(2) a/b rounds towards more negative numbers and a%b is positive. This is
actually the behaviour I prefer, but regrettably it's not available
in a simple way in C99. This is what glibc is doing.

As for Solaris, my best guess is that it's calculating:
'0' + tm_year / 10 % 10
'0' + tm_year % 10
If tm_year is negative and / rounds towards zero, you'd get that behaviour
(the characters ' ( and / are respectively '0'-9, '0'-8, and '0'-1 on an
ASCII system).

--
Clive D.W. Feather  | Work:  <clive at demon.net>   | Tel:    +44 20 8495 6138
Internet Expert     | Home:  <clive at davros.org>  | Fax:    +44 870 051 9937
Demon Internet      | WWW: http://www.davros.org | Mobile: +44 7973 377646
Thus plc            |                            |

```