Domanda

How can I (quickly) calculate the number of Wednesdays that have occurred in the current year? For example a function num_wednesdays() would return 1 when called on January first of 2014, 1 on January 7th, and 2 on January 8th 2014.

Edit This is what I settled on.

int num_wednesdays() {
  time_t now, then;
  struct tm * tmp;
  int today;
  time(&now);

  tmp = localtime(&now);
  today = tmp->tm_yday;
  tmp->tm_mon = 0;  
  tmp->tm_mday = 0;

  do {
    tmp->tm_mday++;
    then = mktime(tmp);
    tmp = localtime(&then);
  } while(tmp->tm_wday != 3);

  if(today < tmp->tm_yday)
    return 0;
  else
    return (today - tmp->tm_yday) / 7 + 1;
}
È stato utile?

Soluzione

Easiest way: since Wednesdays occur every 7 days, you only need to find when the first Wednesday of the year occurred and then calculate the number of 7-day periods since that day.

Altri suggerimenti

The problem can be solved with some modulo arithmetic and a single call to localtime() and no calls to mktime(). The function num_weekday() below will tell you how many of any given day of the week have occurred in the year of the given reference time up to the reference time. If the given time is on the same day of the week, it counts as having occurred.

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

static const int debug = 1;

extern int num_weekday(time_t ref_time, int req_dow);

static int mod(int x, int n)
{
    int r = x % n;
    if (r == 0)
        r = n;
    return r;
}

int num_weekday(time_t ref_time, int req_dow)
{
    assert(req_dow >= 0 && req_dow <= 6);
    struct tm *info = localtime(&ref_time);
    int wday_0101 = 6 - (info->tm_yday + 6 - info->tm_wday) % 7;
    int num_dow = (info->tm_yday + mod(wday_0101 + 7 - req_dow, 7)) / 7;
    if (debug)
    {
        printf("%.4d-%.2d-%.2d: yday = %3d; wday = %d; wday 01-01 = %d; "
                "req dow = %d; num dow = %2d\n",
                info->tm_year + 1900, info->tm_mon + 1, info->tm_mday, info->tm_yday,
                info->tm_wday, wday_0101, req_dow, num_dow);
    }
    return num_dow;
}

static void test_time(time_t ref_time, int req_dow)
{
    int num_days = num_weekday(ref_time, req_dow);
    if (!debug)
    {
        struct tm *info = localtime(&ref_time);
        printf("%.4d-%.2d-%.2d: yday = %3d; wday = %d; "
                "req dow = %d; num dow = %2d\n",
                info->tm_year + 1900, info->tm_mon + 1, info->tm_mday,
                info->tm_yday, info->tm_wday, req_dow, num_days);
    }
}

enum { SECS_PER_DAY  = 24 * 60 * 60         };
enum { SECS_PER_YEAR = 365 * SECS_PER_DAY   };
enum { YEAR_MIN = -6,  YEAR_MAX = -YEAR_MIN };
enum { DAY_MIN  = -15, DAY_MAX  = -DAY_MIN  };

int main(void)
{
    const time_t base = 1388600000;   // 1388600000 = 2014-01-01 18:13:20 +00:00
    for (int req_dow = 0; req_dow <= 6; req_dow++)
    {
        for (int year = YEAR_MIN; year <= YEAR_MAX; year++)
        {
            time_t start = base + year * SECS_PER_YEAR;
            for (int day = DAY_MIN; day <= DAY_MAX; day++)
                test_time(start + day * SECS_PER_DAY, req_dow);
        }
    }

    for (int req_dow = 0; req_dow <= 6; req_dow++)
        test_time(time(0), req_dow);

    return 0;
}

The test code generates a lot of data, including the following output. Tested on Mac OS X 10.9.2, GCC 4.8.2, 64-bit compilation.

…
2013-12-28: yday = 361; wday = 6; wday 01-01 = 2; req dow = 3; num dow = 52
2013-12-29: yday = 362; wday = 0; wday 01-01 = 2; req dow = 3; num dow = 52
2013-12-30: yday = 363; wday = 1; wday 01-01 = 2; req dow = 3; num dow = 52
2013-12-31: yday = 364; wday = 2; wday 01-01 = 2; req dow = 3; num dow = 52
2014-01-01: yday =   0; wday = 3; wday 01-01 = 3; req dow = 3; num dow =  1
2014-01-02: yday =   1; wday = 4; wday 01-01 = 3; req dow = 3; num dow =  1
2014-01-03: yday =   2; wday = 5; wday 01-01 = 3; req dow = 3; num dow =  1
2014-01-04: yday =   3; wday = 6; wday 01-01 = 3; req dow = 3; num dow =  1
2014-01-05: yday =   4; wday = 0; wday 01-01 = 3; req dow = 3; num dow =  1
2014-01-06: yday =   5; wday = 1; wday 01-01 = 3; req dow = 3; num dow =  1
2014-01-07: yday =   6; wday = 2; wday 01-01 = 3; req dow = 3; num dow =  1
2014-01-08: yday =   7; wday = 3; wday 01-01 = 3; req dow = 3; num dow =  2
2014-01-09: yday =   8; wday = 4; wday 01-01 = 3; req dow = 3; num dow =  2
2014-01-10: yday =   9; wday = 5; wday 01-01 = 3; req dow = 3; num dow =  2
2014-01-11: yday =  10; wday = 6; wday 01-01 = 3; req dow = 3; num dow =  2
2014-01-12: yday =  11; wday = 0; wday 01-01 = 3; req dow = 3; num dow =  2
2014-01-13: yday =  12; wday = 1; wday 01-01 = 3; req dow = 3; num dow =  2
2014-01-14: yday =  13; wday = 2; wday 01-01 = 3; req dow = 3; num dow =  2
2014-01-15: yday =  14; wday = 3; wday 01-01 = 3; req dow = 3; num dow =  3
2014-01-16: yday =  15; wday = 4; wday 01-01 = 3; req dow = 3; num dow =  3
2014-12-17: yday = 350; wday = 3; wday 01-01 = 3; req dow = 3; num dow = 51
2014-12-18: yday = 351; wday = 4; wday 01-01 = 3; req dow = 3; num dow = 51
2014-12-19: yday = 352; wday = 5; wday 01-01 = 3; req dow = 3; num dow = 51
2014-12-20: yday = 353; wday = 6; wday 01-01 = 3; req dow = 3; num dow = 51
2014-12-21: yday = 354; wday = 0; wday 01-01 = 3; req dow = 3; num dow = 51
2014-12-22: yday = 355; wday = 1; wday 01-01 = 3; req dow = 3; num dow = 51
2014-12-23: yday = 356; wday = 2; wday 01-01 = 3; req dow = 3; num dow = 51
2014-12-24: yday = 357; wday = 3; wday 01-01 = 3; req dow = 3; num dow = 52
2014-12-25: yday = 358; wday = 4; wday 01-01 = 3; req dow = 3; num dow = 52
2014-12-26: yday = 359; wday = 5; wday 01-01 = 3; req dow = 3; num dow = 52
2014-12-27: yday = 360; wday = 6; wday 01-01 = 3; req dow = 3; num dow = 52
2014-12-28: yday = 361; wday = 0; wday 01-01 = 3; req dow = 3; num dow = 52
2014-12-29: yday = 362; wday = 1; wday 01-01 = 3; req dow = 3; num dow = 52
2014-12-30: yday = 363; wday = 2; wday 01-01 = 3; req dow = 3; num dow = 52
2014-12-31: yday = 364; wday = 3; wday 01-01 = 3; req dow = 3; num dow = 53
2015-01-01: yday =   0; wday = 4; wday 01-01 = 4; req dow = 3; num dow =  0
2015-01-02: yday =   1; wday = 5; wday 01-01 = 4; req dow = 3; num dow =  0
2015-01-03: yday =   2; wday = 6; wday 01-01 = 4; req dow = 3; num dow =  0
2015-01-04: yday =   3; wday = 0; wday 01-01 = 4; req dow = 3; num dow =  0
…
2014-03-15: yday =  73; wday = 6; wday 01-01 = 3; req dow = 0; num dow = 10
2014-03-15: yday =  73; wday = 6; wday 01-01 = 3; req dow = 1; num dow = 10
2014-03-15: yday =  73; wday = 6; wday 01-01 = 3; req dow = 2; num dow = 10
2014-03-15: yday =  73; wday = 6; wday 01-01 = 3; req dow = 3; num dow = 11
2014-03-15: yday =  73; wday = 6; wday 01-01 = 3; req dow = 4; num dow = 11
2014-03-15: yday =  73; wday = 6; wday 01-01 = 3; req dow = 5; num dow = 11
2014-03-15: yday =  73; wday = 6; wday 01-01 = 3; req dow = 6; num dow = 11

Note that it correctly identifies 2014-12-31 as the 53rd Wednesday in 2014.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top