Paul Eggert wrote:

> While testing some code I discovered that the tz strftime week numbers
> are incompatible with the %V week numbers generated by Solaris 2.5.1 strftime
> and with the GNU C Library strftime.  I don't know what the correct
> definition of week numbers is (and I don't particularly want to know :-)

Whether you want to know it or not:    ;-)

%V is used by the date command of POSIX.2 in order to get the ISO 8601
week number (which is very widely used for industrial planning in many
European countries). I understand that %V strftime will be defined in
the revised ISO C standard as well to be ISO 8601. This is therefore
what tz strftime should do. The ISO 8601 week definition is explained
on <URL:http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html>.

In brief:

  - Week numbers can range from 01 to 53. Some years have only
    weeks 01 to 52.
  - Week 1 is the week that includes January 4, which is identical
    to the first week that includes the first Thursday of the new
    year, which is identical to the first week that has the majority
    of its days in the new year.
  - Day one of the week is Monday, day seven is Sunday.

Today (1996-07-17) is day 3 of week 29 of the year 1996 (1996-W29-3).
You can use in the Emacs calendar function the command p c in order to
find the ISO 8601 week number that %V should print if you do not have
a European style calendar on your desk (where the ISO week numbers
serve as a sort of page numbers).

/*
 * Calculate week number and day of week according to ISO 8601.
 * Implementation derived from code provided by L. Kirby.
 */
void get_week_number(const struct tm *t, int *week, int *dayofweek)
{
  int tmp1, tmp2, fourthdaynum, year, isleap;

  tmp1 = 1 - t->tm_wday;
  tmp2 = t->tm_yday + ((tmp1 > 0) ? 3 : 10) + tmp1;
  fourthdaynum = tmp2 % 7;
    
  *week = tmp2 / 7;

  if (*week == 0) {
    year = t->tm_year + 1900 - 1;
    isleap = !(year % 4) && ((year % 100) || !(year % 400));
    *week = (fourthdaynum + isleap >= 6) ? 53 : 52;
  } else if (*week == 53) {
    year = t->tm_year + 1900;
    isleap = !(year % 4) && ((year % 100) || !(year % 400));
    if (fourthdaynum > isleap)
      *week = 1;
  }

  if (t->tm_wday == 0)
    *dayofweek = 7;
  else
    *dayofweek = t->tm_wday;

  return;
}

Markus

-- 
Markus Kuhn, Computer Science student -- University of Erlangen,
Internet Mail: <mskuhn@cip.informatik.uni-erlangen.de> - Germany
WWW Home: <http://wwwcip.informatik.uni-erlangen.de/user/mskuhn>

