Hasan Avşar
Hasan Avşar

Reputation: 43

ISO 8601 week number in C

I am trying to get the ISO8601 week number with C. MinGW is installed on my PC. GCC version is 5.3.0. You can see my code below. strftime doesn't work for specifier "%V". But it works fine with the specifier "%W". But that's not what I want. I need the week number of year in ISO 8601 format.

I have tried my code with 2 different online C compilers and they both worked fine. I doubt that the compiler on my PC is not well configured. Can anyone tell me what am I doing wrong? Any help would be appreciated.

Here is my code:

#include <stdio.h>
#include <time.h>
#include <string.h>

int main ()
{
    time_t timep;
    struct tm * time_inf;
    char buff [80];

    time ( &timep );
    time_inf = localtime ( &timep );

    time_inf->tm_year = 2008 - 1900;
    time_inf->tm_mon = 11;
    time_inf->tm_mday = 31;

    mktime ( time_inf );

    strftime (buff, sizeof(buff), "%V", time_inf) ;
    puts (buff); //prints nothing

    printf("%d", strlen(buff)); //prints 0

    return 0;
}

Upvotes: 2

Views: 1944

Answers (2)

chux
chux

Reputation: 153498

to get the ISO8601 week number with C

When "%V" with strftime() is not available or problematic, code can directivity calculate the ISO 8601 week.


ISO 8601 weeks of the year begins on Mondays.

When one want to find the ISO 8601 week of the year, often the corresponding "year" is needed too.

The first week of the year, week #1, is the first week, starting on Monday, that has at least 4 days in January - or as code below uses, the first Thursday of the year is in week 1.

Is is possible that Dec 31 is in week 1 of the next year.
Is is possible that Jan 1 is in week 52/53 of the previous year.

#include <time.h>

// return 1 on failure, 0 on success
int tm_YearWeek(const struct tm *tmptr, int *year, int *week) {
  // work with local copy
  struct tm tm = *tmptr;
  // fully populate the yday and wday fields.
  if (mktime(&tm) == -1) {
    return 1;
  }

  // Find day-of-the-week: 0 to 6.
  // Week starts on Monday per ISO 8601
  // 0 <= DayOfTheWeek <= 6, Monday, Tuesday ... Sunday
  int DayOfTheWeek = (tm.tm_wday + (7 - 1)) % 7;

  // Offset the month day to the Monday of the week.
  tm.tm_mday -= DayOfTheWeek;
  // Offset the month day to the mid-week (Thursday) of the week, 3 days later.
  tm.tm_mday += 3;
  // Re-evaluate tm_year and tm_yday  (local time)
  if (mktime(&tm) == -1) {
    return 1;
  }

  *year = tm.tm_year + 1900;
  // Convert yday to week of the year, stating with 1.
  *week = tm.tm_yday / 7 + 1;
  return 0;
}

Example

int main() {
  struct tm tm = { 0 };
  tm.tm_year = 2008 - 1900;
  tm.tm_mon = 12 - 1;
  tm.tm_mday = 31;
  tm.tm_isdst = -1;
  int y = 0, w = 0;
  int err = tm_YearWeek(&tm, &y, &w);
  printf("Err:%d  Year:%d  Week:%d %02d%02d\n", err, y, w, y%100, w);
  return 0;
}

Output is week 1 of 2009 for Dec 31, 2008 or 0901. This is expected per the discussion above and may explain OP's unstated concern with OP's code.

Err:0  Year:2009  Week:1 0901

Upvotes: 2

a3f
a3f

Reputation: 8657

MinGW doesn't provide its own strftime, but links in MSVCRT's definition, which doesn't provide %V.

Either implement what you're missing yourself or use an alternate implementation, e.g. here's BSD's strftime.

Upvotes: 2

Related Questions