From: Jason Green Newsgroups: comp.os.msdos.djgpp Subject: Re: strftime: Need Help with Time Offsets Date: Sat, 06 Jan 2001 11:46:51 +0000 Organization: Customer of Energis Squared Lines: 146 Message-ID: References: <1a524t0tk28cmv3vqfq26tooe0qeikhgm5 AT 4ax DOT com> <2561-Fri22Dec2000120234+0200-eliz AT is DOT elta DOT co DOT il> <1190-Fri22Dec2000173248+0200-eliz AT is DOT elta DOT co DOT il> <0nt94tkh5ptfohe9414da1u3geja7ml4vm AT 4ax DOT com> <20001226124727 DOT A19514 AT kendall DOT sfbr DOT org> <419i4tsoc9dgtbp9okme2cghdn09uocgq4 AT 4ax DOT com> <86pofxnajiq DOT fsf AT sirppi DOT helsinki DOT fi> NNTP-Posting-Host: modem-227.titanium.dialup.pol.co.uk Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Trace: news6.svr.pol.co.uk 978781621 20766 62.136.21.227 (6 Jan 2001 11:47:01 GMT) NNTP-Posting-Date: 6 Jan 2001 11:47:01 GMT X-Complaints-To: abuse AT theplanet DOT net X-Newsreader: Forte Agent 1.7/32.534 To: djgpp AT delorie DOT com DJ-Gateway: from newsgroup comp.os.msdos.djgpp Reply-To: djgpp AT delorie DOT com Esa A E Peuha 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 #include #include #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; }