static unsigned int __bizda_get_yday(dt_bizda_t that, dt_bizda_param_t param) { /* return the N-th business day in Y, * the meaning of ultimo will be stretched to Y-ultimo, either last year's * or this year's, other reference points are not yet supported * * we use the following table (days beyond 20 bdays per month (across)): * Mon 3 0 2 1 3 1 2 3 0 3 2 1 * Mon 3 1 1 rest like Tue * Tue 3 0 1 2 3 0 3 2 1 3 1 2 * Tue 3 1 1 rest like Wed * Wed 3 0 1 2 2 1 3 1 2 3 0 3 * Wed 3 0 2 rest like Thu * Thu 2 0 2 2 1 2 3 1 2 2 1 3 * Thu 2 0 3 rest like Fri * Fri 1 0 3 2 1 2 2 2 2 1 2 3 * Fri 1 1 3 rest like Sat * Sat 1 0 3 1 2 2 1 3 2 1 2 2 * Sat 1 1 3 rest like Sun * Sun 2 0 3 0 3 2 1 3 1 2 2 1 * Sun 2 1 2 rest like Mon * */ struct __bdays_by_wday_s { unsigned int jan:2; unsigned int feb:2; unsigned int mar:2; unsigned int apr:2; unsigned int may:2; unsigned int jun:2; unsigned int jul:2; unsigned int aug:2; unsigned int sep:2; unsigned int oct:2; unsigned int nov:2; unsigned int dec:2; unsigned int feb_leap:2; unsigned int mar_leap:2; /* 4 bits left */ unsigned int flags:4; }; static struct __bdays_by_wday_s tbl[8U] = { { /* DT_MIRACLEDAY */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* DT_MONDAY */ 3, 0, 2, 1, 3, 1, 2, 3, 0, 3, 2, 1, 1, 1, 0 }, { /* DT_TUESDAY */ 3, 0, 1, 2, 3, 0, 3, 2, 1, 3, 1, 2, 1, 1, 0 }, { /* DT_WEDNESDAY */ 3, 0, 1, 2, 2, 1, 3, 1, 2, 3, 0, 3, 0, 2, 0 }, { /* DT_THURSDAY */ 2, 0, 2, 2, 1, 2, 3, 1, 2, 2, 1, 3, 0, 3, 0 }, { /* DT_FRIDAY */ 1, 0, 3, 2, 1, 2, 2, 2, 2, 1, 2, 3, 1, 3, 0 }, { /* DT_SATURDAY */ 1, 0, 3, 1, 2, 2, 1, 3, 2, 1, 2, 2, 1, 3, 0 }, { /* DT_SUNDAY */ 2, 0, 3, 0, 3, 2, 1, 3, 1, 2, 2, 1, 1, 2, 0 }, }; dt_dow_t j01wd; unsigned int y = that.y; unsigned int m = that.m; unsigned int accum = 0; if (UNLIKELY(param.ref != BIZDA_ULTIMO)) { return 0; } j01wd = __get_jan01_wday(that.y); if (LIKELY(!__leapp(y))) { union { uint32_t u; uint32_t lu:2; struct __bdays_by_wday_s s; } page = { .s = tbl[j01wd], }; for (unsigned int i = 0; i < m - 1; i++) { accum += page.lu; #if BYTE_ORDER == BIG_ENDIAN page.u <<= 2; #elif BYTE_ORDER == LITTLE_ENDIAN page.u >>= 2; #else # warning unknown byte order #endif /* BYTE_ORDER */ } } else if (m > 1) {
DEFUN unsigned int __ymcw_get_yday(dt_ymcw_t that) { /* return the N-th W-day in Y, this is equivalent with 8601's Y-W-D calendar * where W is the week of the year and D the day in the week */ /* if a year starts on W, then it's * 5 Ws in jan * 4 Ws in feb * 4 Ws in mar * 5 Ws in apr * 4 Ws in may * 4 Ws in jun * 5 Ws in jul * 4 Ws in aug * 4 + leap Ws in sep * 5 - leap Ws in oct * 4 Ws in nov * 5 Ws in dec, * so go back to the last W, and compute its number instead * * Here's the full schema: * For W+0 * 5 4 4 5 4 4 5 4 4 5 4 5 non-leap * 5 4 4 5 4 4 5 4 5 4 4 5 leap flip9 * * For W+1 * 5 4 4 4 5 4 5 4 4 5 4 4 non-leap * 5 4 4 5 4 4 5 4 4 5 4 5 leap flip4 flip12 * * For W+2 * 5 4 4 4 5 4 4 5 4 5 4 4 non-leap * 5 4 4 4 5 4 5 4 4 5 4 4 leap flip7 * * For W+3 * 4 4 5 4 5 4 4 5 4 4 5 4 non-leap * 4 5 4 4 5 4 4 5 4 5 4 4 leap flip2 flip10 * * For W+4 * 4 4 5 4 4 5 4 5 4 4 5 4 non-leap * 4 4 5 4 5 4 4 5 4 4 5 4 leap flip5 * * For W+5 * 4 4 5 4 4 5 4 4 5 4 4 5 non-leap * 4 4 5 4 4 5 4 5 4 4 5 4 leap flip8 flip11 * * For W+6 * 4 4 4 5 4 4 5 4 5 4 4 5 non-leap * 4 4 5 4 4 5 4 4 5 4 4 5 leap flip3 flip6 * * flipN denotes which month in a leap year becomes 5 where the * month in the non-leap year equivalent has value 4. * * The flips for W+1 W+2, W+4, W+5, W+6 can be presented through * non-leap rules: * * 544544544545544544544545 * 544544545445544544545445 * * 544454544544544454544544 * 544544544545544544544545 = non-leap W+0 * * 544454454544544454454544 * 544454544544544454544544 = non-leap W+1 * * 445454454454445454454454 * 454454454544454454454544 * * 445445454454445445454454 * 445454454454445454454454 = non-leap W+3 * * 445445445445445445445445 * 445445454454445445454454 = non-leap W+4 * * 444544545445444544545445 * 445445445445445445445445 = non-leap W+5 */ static uint8_t ycum[][12] = { { /* W+0 */ 0, 5, 9, 13, 18, 22, 26, 31, 35, 39, 44, 48, /*53*/ }, { /* W+1 */ 0, 5, 9, 13, 17, 22, 26, 31, 35, 39, 44, 48, /*52*/ }, { /* W+2 */ 0, 5, 9, 13, 17, 22, 26, 30, 35, 39, 44, 48, /*52*/ }, { /* W+3 */ 0, 4, 8, 13, 17, 22, 26, 30, 35, 39, 43, 48, /*52*/ }, { /* W+4 */ 0, 4, 8, 13, 17, 21, 26, 30, 35, 39, 43, 48, /*52*/ }, { /* W+5 */ 0, 4, 8, 13, 17, 21, 26, 30, 34, 39, 43, 47, /*52*/ }, { /* W+6 */ 0, 4, 8, 12, 17, 21, 25, 30, 34, 39, 43, 47, /*52*/ }, { /* leap-year rule W+0 */ 0, 5, 9, 13, 18, 22, 26, 31, 35, 40, 44, 48, /*53*/ /* leap-year rule W+3 = W+0 + 1mo + 4 */ }, }; dt_dow_t j01w = __get_jan01_wday(that.y); unsigned int diff = j01w <= that.w ? that.w - j01w : that.w + 7 - j01w; if (UNLIKELY(__leapp(that.y))) { switch (diff) { case 3: if (UNLIKELY(that.m < 2)) { return that.c; } return that.c + (ycum[7])[that.m - 2] + 4; case 0: return that.c + (ycum[7])[that.m - 1]; default: case 1: case 2: case 4: case 5: case 6: diff--; break; } } return that.c + (ycum[diff])[that.m - 1]; }