Hello! I've recently been 'dabbling' in dates and in particular ISO8601 week numbers so I was interested in tzcode96b.tar.gz, in particular the strftime.c file. First however I'll just point out something minor in tzfile.h which is: #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) This is not the best way to test for a leap year since if the year is not divisible by 4 we know it is not divisible by 400 (but it tests for this anyway). The more usual form is: #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) My main interest is in the following extract from the code for the 'V' (amongst others) conversion specifier: #ifdef XPG4_1994_04_09 if (w == 52 && t->tm_mon == TM_JANUARY) w = 53; #endif /* defined XPG4_1994_04_09 */ Is it true that XPG4 has a slightly different definition of week number than ISO8601? What this appears to be saying is that if week 52 crosses into the new year the days in January become week 53 (but if week 53 crosses the year boundary it stays as week 53). The following is the function I wrote to calculate ISO8601 week numbers. I've added an 'XPG4' option in what I believe to be an equivalent way (this means that points 2 and 6 of the 'rules' aren't quite correct for XPG4). Since I'm submitting something similar for inclusion in the free 'Snippets' library any thoughts would be welcome. /****************************************************************************** * weeknum_ISO8601 January 1996 L.Kirby * * Released to the Public Domain * * Calculates the week number of a day in the year based on the ISO8601 week * numbering scheme. The arguments are: * * t - a pointer to a struct tm in which the following members must be set and * normalised to the standard ranges specified (as standard library * functions gmtime, localtime and mktime should do): * * tm_wday - The day of the week of the day in question: * 0-Sunday -> 6-Saturday * * tm_yday - The day of the year of the day in question: 0 -> 365 * January 1st is day 0. * * tm_year - The year since 1900. * * firstdow - This defines the day of the week on which a week starts: * 0-Sunday -> 6-Saturday. For normal ISO8601 weeks that start on * a Monday this should be 1. * ****************************************************************************** * * The week number is a value between 1 and 53 inclusive defined according to * the following rules: * * 1. The Gregorian calendar is assumed. * * 2. There are always 7 consecutive days with the same week number. * * 3. January 4th is defined to be in week 1. Equivalently week 1 is the * first week of a year which has at least 4 days in that year. * * 4. firstdow defines the day of the week which starts a new week i.e. has * a different week number from the previous day. * * 5. Week numbers increase in sequence from week 1 until the week that is * defined to be week 1 of the following year. * * It follows that: * * 6. Up to January 3rd may be in either week 1 of the current year or in * weeks 52 or 53 of the previous year. * * 7. 29th December onwards may be in either weeks 52 or 53 of the current * year or week 1 of the following year. * ****************************************************************************** */ #include <time.h> #define isleap(year) (!((year) % 4) && (((year) % 100) || !((year) % 400))) int weeknum_ISO8601(const struct tm *t, int firstdow) { const int tmp1 = firstdow - t->tm_wday; const int tmp2 = t->tm_yday + ((tmp1 > 0) ? 3 : 10) + tmp1; const int fourthdaynum = tmp2 % 7; int week = tmp2 / 7; if (week == 0) { #ifdef XPG4_1994_04_09 week = 53; #else const int year = t->tm_year + (1900 % 400) - 1; week = (fourthdaynum + isleap(year) >= 6) ? 53 : 52; #endif } else if (week == 53) { const int year = t->tm_year + (1900 % 400); if (fourthdaynum > isleap(year)) week = 1; } return week; } -- ----------------------------------------- Lawrence Kirby | fred@genesis.demon.co.uk Wilts, England | 70734.126@compuserve.com -----------------------------------------
participants (1)
-
fred@genesis.demon.co.uk