Esempio n. 1
0
static struct dt_ddur_s
__ymcw_diff(dt_ymcw_t d1, dt_ymcw_t d2)
{
/* compute d2 - d1 entirely in terms of ymd */
	struct dt_ddur_s res = dt_make_ddur(DT_DURYMCW, 0);
	signed int tgtd;
	signed int tgtm;
	dt_dow_t wd01, wd02;

	if (__ymcw_cmp(d1, d2) > 0) {
		dt_ymcw_t tmp = d1;
		d1 = d2;
		d2 = tmp;
		res.neg = 1;
	}

	wd01 = __get_m01_wday(d1.y, d1.m);
	if (d2.y != d1.y || d2.m != d1.m) {
		wd02 = __get_m01_wday(d2.y, d2.m);
	} else {
		wd02 = wd01;
	}

	/* first compute the difference in months Y2-M2-01 - Y1-M1-01 */
	tgtm = GREG_MONTHS_P_YEAR * (d2.y - d1.y) + (d2.m - d1.m);
	/* using the firsts of the month WD01, represent d1 and d2 as
	 * the C-th WD01 plus OFF */
	{
		unsigned int off1;
		unsigned int off2;

		off1 = __uimod(d1.w - wd01, GREG_DAYS_P_WEEK);
		off2 = __uimod(d2.w - wd02, GREG_DAYS_P_WEEK);
		tgtd = off2 - off1 + GREG_DAYS_P_WEEK * (d2.c - d1.c);
	}

	/* fixups */
	if (tgtd < (signed int)GREG_DAYS_P_WEEK && tgtm > 0) {
		/* if tgtm is 0 it remains 0 and tgtd remains negative */
		/* get the target month's mdays */
		unsigned int d2m = d2.m;
		unsigned int d2y = d2.y;

		if (--d2m < 1) {
			d2m = GREG_MONTHS_P_YEAR;
			d2y--;
		}
		tgtd += __get_mdays(d2y, d2m);
		tgtm--;
	}

	/* fill in the results */
	res.ymcw.y = tgtm / GREG_MONTHS_P_YEAR;
	res.ymcw.m = tgtm % GREG_MONTHS_P_YEAR;
	res.ymcw.c = tgtd / GREG_DAYS_P_WEEK;
	res.ymcw.w = tgtd % GREG_DAYS_P_WEEK;
	return res;
}
Esempio n. 2
0
DEFUN unsigned int
__get_bdays(unsigned int y, unsigned int m)
{
/* the 28th exists in every month, and it's exactly 20 bdays
 * away from the first, oh and it's -1 mod 7
 * then to get the number of bdays remaining in the month
 * from the number of days remaining in the month R
 * we use a multiplication table, downwards the weekday of the
 * 28th, rightwards the days in excess of the 28th
 * Miracleday is only there to make the left hand side of the
 * multiplication 3 bits wide:
 *
 * r->  0  1  2  3
 * Sun  0  1  2  3
 * Mon  0  1  2  3
 * Tue  0  1  2  3
 * Wed  0  1  2  2
 * Thu  0  1  1  1
 * Fri  0  0  0  1
 * Sat  0  0  1  2
 * Mir  0  0  0  0
 */
	unsigned int md = __get_mdays(y, m);
	unsigned int rd = (unsigned int)(md - 28U);
	dt_dow_t m01wd;
	unsigned int m28wd;

	/* rd should not overflow */
	assert((signed int)md - 28 >= 0);

	/* wday of the 1st and 28th */
	m01wd = __get_m01_wday(y, m);
	m28wd = __uimod((signed int)m01wd - 1, GREG_DAYS_P_WEEK);
	if (LIKELY(rd > 0)) {
		switch ((dt_dow_t)m28wd) {
		case DT_SUNDAY:
		case DT_MONDAY:
		case DT_TUESDAY:
			return 20 + rd;
		case DT_WEDNESDAY:
			return 20 + rd - (rd == 3);
		case DT_THURSDAY:
			return 21;
		case DT_FRIDAY:
			return 20 + (rd == 3);
		case DT_SATURDAY:
			return 20 + rd - 1;
		case DT_MIRACLEDAY:
		default:
			abort();
		}
	}
	return 20U;
}
Esempio n. 3
0
DEFUN int
__ymcw_cmp(dt_ymcw_t d1, dt_ymcw_t d2)
{
	if (d1.y < d2.y) {
		return -1;
	} else if (d1.y > d2.y) {
		return 1;
	} else if (d1.m < d2.m) {
		return -1;
	} else if (d1.m > d2.m) {
		return 1;
	}

	/* we're down to counts, however, the last W of a month is always
	 * count 5, even though counting forward it would be 4 */
	if (d1.c < d2.c) {
		return -1;
	} else if (d1.c > d2.c) {
		return 1;
	}
	/* now it's up to the first of the month */
	{
		dt_dow_t wd01;
		unsigned int off1;
		unsigned int off2;

		wd01 = __get_m01_wday(d1.y, d1.m);
		/* represent cw as C-th WD01 + OFF */
		off1 = __uimod(d1.w - wd01, GREG_DAYS_P_WEEK);
		off2 = __uimod(d2.w - wd01, GREG_DAYS_P_WEEK);

		if (off1 < off2) {
			return -1;
		} else if (off1 > off2) {
			return 1;
		} else {
			return 0;
		}
	}
}