Mail Archives: djgpp/2001/01/06/07:06:42
Esa A E Peuha <peuha AT cc DOT helsinki DOT fi> wrote:
> > The week number, %V as defined above, needs to be calculated from the
> > date fields of a struct tm.
>
> Here's (pseudo)code to compute the week number and the year that the
> week belongs to (this assumes that the fields in struct tm are in valid
> ranges):
Thankyou.
> This uses two helper functions. The leap year checking one is simple:
>
> is_leap_year(year)
> {
> return (year % 4 == 0) - (year % 100 == 0) + (year % 400 == 100);
> }
This is buggy (try it for year 2000), but that's ok because DJGPP
already has a leap year macro which can be copied.
> The other is not (this could obviously be optimized, but this way it's
> hopefully rather self-explanatory):
Erm, sorry, this is not obvious to me. Although that's probably more
to do with damage suffered staring at date maths code. ;-)
> I hope this is of some use to you.
Yes, it is of use (to DJGPP), thankyou for looking at this.
I put your code into functions. Unfortunately, it sometimes gets the
week number wrong where week 52/53 overlaps into the new year. In the
year range 1970-2030, the following days have the wrong week number:
> Sat, 01 Jan 1972 - 1971:53
> Sun, 02 Jan 1972 - 1971:53
> Sat, 01 Jan 1977 - 1976:52
> Sun, 02 Jan 1977 - 1976:52
> Sat, 01 Jan 2000 - 1999:53
> Sun, 02 Jan 2000 - 1999:53
> Sat, 01 Jan 2005 - 2004:52
> Sun, 02 Jan 2005 - 2004:52
> Sat, 01 Jan 2028 - 2027:53
> Sun, 02 Jan 2028 - 2027:53
Here is the code I tested:
#include <stdio.h>
#include <time.h>
#include <string.h>
#define TM_YEAR_BASE 1900
/* Leap year calculation (ripped from txfile.h) */
#define isleap(y) \
((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
/* number_of_week: Helper function to iso_week_num()
*/
static int
number_of_week (int wday, int yday)
{
int day_of_week_now = (wday + 6) % 7;
int day_of_week_jan1 = (day_of_week_now + 53 * 7 - yday) % 7;
int days_since_monday_of_first_week = yday + day_of_week_jan1 - 7
* (day_of_week_jan1 >= 4);
return days_since_monday_of_first_week / 7 + 1;
}
/* iso_year: Calculates an adjustment for tm_year to account for
ISO-8601 dates as used by %v, %g and %G. Returns -1, 0, or 1
which can be added to tm_year to determine the ISO-8601 year.
*/
static int
iso_year_adjust (const struct tm *t)
{
if (t->tm_mon == 11 &&
((t->tm_wday == 1 && t->tm_mday >= 29) ||
(t->tm_wday == 2 && t->tm_mday >= 30) ||
(t->tm_wday == 3 && t->tm_mday == 31)))
/* day belongs to first week of next year */
return 1;
else if (t->tm_mon == 0 &&
((t->tm_wday == 5 && t->tm_mday == 1) ||
(t->tm_wday == 6 && t->tm_mday <= 2) ||
(t->tm_wday == 0 && t->tm_mday <= 3)))
/* day belongs to last week of previous year */
return -1;
else
/* the usual case */
return 0;
}
/* iso_week_num: Returns the ISO-8601 week number as required by %V.
*/
static int
iso_week_num (const struct tm *t)
{
switch (iso_year_adjust (t))
{
case 1:
return 1;
case -1:
/* day belongs to last week of previous year */
return number_of_week (t->tm_wday,
t->tm_yday +
((isleap(t->tm_year + TM_YEAR_BASE)) ?
366:365));
default:
/* the usual case */
return number_of_week (t->tm_wday, t->tm_yday);
}
}
int
main (void)
{
char str[80];
struct tm tm;
int year, day;
for (year = 1970; year < 2030; year++)
{
for (day = 21; day <= 41; day++)
{
memset (&tm, 0, sizeof (tm));
tm.tm_mday = day;
tm.tm_mon = 11;
tm.tm_year = year - 1900;
mktime (&tm);
strftime (str, sizeof (str), "%a, %d %b %Y", &tm);
printf ("%s - %d:%02d\n", str,
tm.tm_year + iso_year_adjust (&tm) + TM_YEAR_BASE,
iso_week_num (&tm));
}
putchar ('\n');
}
return 0;
}
- Raw text -