delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2001/01/06/07:06:42

From: Jason Green <news AT jgreen4 DOT fsnet DOT co DOT uk>
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: <t21e5t4m6auc7k7vqlj78cv0c8qg1gngfh@4ax.com>
References: <1a524t0tk28cmv3vqfq26tooe0qeikhgm5 AT 4ax DOT com> <Pine DOT SUN DOT 3 DOT 91 DOT 1001221110346 DOT 28580O-100000 AT is> <ku454tke181c70f6rimuamfd2pc9p0blfk AT 4ax DOT com> <2561-Fri22Dec2000120234+0200-eliz AT is DOT elta DOT co DOT il> <pki64tssb5jku2tjnqg3ch5oqr5ngevntk AT 4ax DOT com> <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
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 <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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019