Beispiel #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;
}
Beispiel #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;
	dt_dow_t m28wd;

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

	/* wday of the 1st and 28th */
	m01wd = __get_m01_wday(y, m);
	m28wd = (dt_dow_t)(m01wd - 1 ?: DT_SUNDAY);
	if (LIKELY(rd > 0)) {
		switch (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;
}
Beispiel #3
0
static unsigned int
__bizda_get_mday(dt_bizda_t that)
{
	dt_dow_t wd01;
	unsigned int res;

	/* find first of the month first */
	wd01 = __get_m01_wday(that.y, that.m);

	switch (wd01) {
	case DT_MONDAY:
	case DT_TUESDAY:
	case DT_WEDNESDAY:
	case DT_THURSDAY:
	case DT_FRIDAY:
		res = 1;
		break;
	case DT_SATURDAY:
		wd01 = DT_MONDAY;
		res = 3;
		break;
	case DT_SUNDAY:
		wd01 = DT_MONDAY;
		res = 2;
		break;
	case DT_MIRACLEDAY:
	default:
		res = 0;
		break;
	}
	/* now just add up bdays */
	{
		unsigned int wk;
		unsigned int nd;
		unsigned int b = that.bd;
		unsigned int magic = (b - 1 + wd01 - 1);

		assert(b + wd01 >= 2);
		wk = magic / DUWW_BDAYS_P_WEEK;
		nd = magic % DUWW_BDAYS_P_WEEK;
		res += wk * GREG_DAYS_P_WEEK + nd - wd01 + 1;
	}
	/* fixup mdays */
	if (res > __get_mdays(that.y, that.m)) {
		res = 0;
	}
	return res;
}
Beispiel #4
0
static unsigned int
__ymcw_get_mday(dt_ymcw_t that)
{
	unsigned int wd01;
	unsigned int res;

	/* see what weekday the first of the month was*/
	wd01 = __get_m01_wday(that.y, that.m);

	/* first WD1 is 1, second WD1 is 8, third WD1 is 15, etc.
	 * so the first WDx with WDx > WD1 is on (WDx - WD1) + 1 */
	res = (that.w + GREG_DAYS_P_WEEK - wd01) % GREG_DAYS_P_WEEK + 1;
	res += GREG_DAYS_P_WEEK * (that.c - 1);
	/* not all months have a 5th X, so check for this */
	if (res > __get_mdays(that.y, that.m)) {
		 /* 5th = 4th in that case */
		res -= GREG_DAYS_P_WEEK;
	}
	return res;
}
Beispiel #5
0
static __attribute__((pure)) unsigned int
__get_mcnt(unsigned int y, unsigned int m, dt_dow_t w)
{
/* get the number of weekdays W in Y-M, which is the max count
 * for a weekday W in ymcw dates in year Y and month M */
	dt_dow_t wd01 = __get_m01_wday(y, m);
	unsigned int md = __get_mdays(y, m);
	/* the maximum number of WD01s in Y-M */
	unsigned int wd01cnt = (md - 1) / GREG_DAYS_P_WEEK + 1;
	/* modulus */
	unsigned int wd01mod = (md - 1) % GREG_DAYS_P_WEEK;

	/* now the next WD01MOD days also have WD01CNT occurrences
	 * if wd01 + wd01mod exceeds the DAYS_PER_WEEK barrier wrap
	 * around by extending W to W + DAYS_PER_WEEK */
	if ((w >= wd01 && w <= wd01 + wd01mod) ||
	    (w + GREG_DAYS_P_WEEK) <= wd01 + wd01mod) {
		return wd01cnt;
	} else {
		return wd01cnt - 1;
	}
}
Beispiel #6
0
echs_instant_t
echs_instant_add(echs_instant_t bas, echs_idiff_t add)
{
	echs_instant_t res = bas;
	int dd = add.d / (int)MSECS_PER_DAY;
	int msd = add.d % (int)MSECS_PER_DAY;
	int car, cdr;

	if (UNLIKELY(echs_instant_all_day_p(bas))) {
		/* just fix up the day, dom and year portion */
		goto fixup_d;
	} else if (UNLIKELY(echs_instant_all_sec_p(bas))) {
		/* just fix up the sec, min, ... portions */
		msd /= (int)MSECS_PER_SEC;
		goto fixup_S;
	}

	car = (res.ms + msd) / (int)MSECS_PER_SEC;
	if ((cdr = (res.ms + msd) % (int)MSECS_PER_SEC) >= 0) {
		res.ms = cdr;
	} else {
		res.ms = cdr + MSECS_PER_SEC;
		car--;
	}
	msd = car;
fixup_S:
	car = (res.S + msd) / (int)SECS_PER_MIN;
	if ((cdr = (res.S + msd) % (int)SECS_PER_MIN) >= 0) {
		res.S = cdr;
	} else {
		res.S = cdr + SECS_PER_MIN;
		car--;
	}
	msd = car;

	car = ((int)res.M + msd) / (int)MINS_PER_HOUR;
	if ((cdr = ((int)res.M + msd) % (int)MINS_PER_HOUR) >= 0) {
		res.M = cdr;
	} else {
		res.M = cdr + MINS_PER_HOUR;
		car--;
	}
	msd = car;

	car = (res.H + msd) / (int)HOURS_PER_DAY;
	if ((cdr = (res.H + msd) % (int)HOURS_PER_DAY) >= 0) {
		res.H = cdr;
	} else {
		res.H = cdr + HOURS_PER_DAY;
		car--;
	}
	msd = car;

	/* get ready to adjust the day */
	if (UNLIKELY(msd)) {
		dd += msd;
	}
	if (dd) {
		int y;
		int m;
		int d;

	fixup_d:
		y = bas.y;
		m = bas.m;
		d = bas.d + dd;

		if (LIKELY(d >= 1 && d <= 28)) {
			/* all months in our design range have 28 days */
			;
		} else if (d < 1) {
			int mdays;

			do {
				if (UNLIKELY(--m < 1)) {
					--y;
					m = 12;
				}
				mdays = __get_mdays(y, m);
				d += mdays;
			} while (d < 1);

		} else {
			int mdays;

			while (d > (mdays = __get_mdays(y, m))) {
				d -= mdays;
				if (UNLIKELY(++m > 12)) {
					++y;
					m = 1;
				}
			}
		}

		res.d = d;
		res.m = m;
		res.y = y;
	}
	return res;
}
Beispiel #7
0
echs_instant_t
echs_instant_fixup(echs_instant_t e)
{
/* this is basically __ymd_fixup_d of dateutils
 * we only care about additive cockups though because instants are
 * chronologically ascending */
	unsigned int md;

	if (UNLIKELY(echs_instant_all_day_p(e))) {
		/* just fix up the day, dom and year portion */
		goto fixup_d;
	} else if (UNLIKELY(echs_instant_all_sec_p(e))) {
		/* just fix up the sec, min, ... portions */
		goto fixup_S;
	}

	if (UNLIKELY(e.ms >= MSECS_PER_SEC)) {
		unsigned int dS = e.ms / MSECS_PER_SEC;
		unsigned int ms = e.ms % MSECS_PER_SEC;

		e.ms = ms;
		e.S += dS;
	}

fixup_S:
	if (UNLIKELY(e.S >= SECS_PER_MIN)) {
		/* leap seconds? */
		unsigned int dM = e.S / SECS_PER_MIN;
		unsigned int S = e.S % SECS_PER_MIN;

		e.S = S;
		e.M += dM;
	}
	if (UNLIKELY(e.M >= MINS_PER_HOUR)) {
		unsigned int dH = e.M / MINS_PER_HOUR;
		unsigned int M = e.M % MINS_PER_HOUR;

		e.M = M;
		e.H += dH;
	}
	if (UNLIKELY(e.H >= HOURS_PER_DAY)) {
		unsigned int dd = e.H / HOURS_PER_DAY;
		unsigned int H = e.H % HOURS_PER_DAY;

		e.H = H;
		e.d += dd;
	}

fixup_d:
refix_ym:
	if (UNLIKELY(e.m > 12U)) {
		unsigned int dy = (e.m - 1) / 12U;
		unsigned int m = (e.m - 1) % 12U + 1U;

		e.m = m;
		e.y += dy;
	}

	if (UNLIKELY(e.d > (md = __get_mdays(e.y, e.m)))) {
		e.d -= md;
		e.m++;
		goto refix_ym;
	}
	return e;
}
Beispiel #8
0
static struct dt_d_s
dround_ddur(struct dt_d_s d, struct dt_ddur_s dur, bool nextp)
{
	switch (dur.durtyp) {
		unsigned int tgt;
		bool forw;
	case DT_DURD:
		if (dur.dv > 0) {
			tgt = dur.dv;
			forw = true;
		} else if (dur.dv < 0) {
			tgt = -dur.dv;
			forw = false;
		} else {
			/* user is an idiot */
			break;
		}

		switch (d.typ) {
			unsigned int mdays;
		case DT_YMD:
			if ((forw && d.ymd.d < tgt) ||
			    (!forw && d.ymd.d > tgt)) {
				/* no month or year adjustment */
				;
			} else if (d.ymd.d == tgt && !nextp) {
				/* we're ON the date already and no
				 * next/prev date is requested */
				;
			} else if (forw) {
				if (LIKELY(d.ymd.m < GREG_MONTHS_P_YEAR)) {
					d.ymd.m++;
				} else {
					d.ymd.m = 1;
					d.ymd.y++;
				}
			} else {
				if (UNLIKELY(--d.ymd.m < 1)) {
					d.ymd.m = GREG_MONTHS_P_YEAR;
					d.ymd.y--;
				}
			}
			/* get ultimo */
			mdays = __get_mdays(d.ymd.y, d.ymd.m);
			if (UNLIKELY(tgt > mdays)) {
				tgt = mdays;
			}
			/* final assignment */
			d.ymd.d = tgt;
			break;
		default:
			break;
		}
		break;

	case DT_DURBD:
		/* bizsis only work on bizsidurs atm */
		if (dur.dv > 0) {
			tgt = dur.dv;
			forw = true;
		} else if (dur.dv < 0) {
			tgt = -dur.dv;
			forw = false;
		} else {
			/* user is an idiot */
			break;
		}

		switch (d.typ) {
			unsigned int bdays;
		case DT_BIZDA:
			if ((forw && d.bizda.bd < tgt) ||
			    (!forw && d.bizda.bd > tgt)) {
				/* no month or year adjustment */
				;
			} else if (d.bizda.bd == tgt && !nextp) {
				/* we're ON the date already and no
				 * next/prev date is requested */
				;
			} else if (forw) {
				if (LIKELY(d.bizda.m < GREG_MONTHS_P_YEAR)) {
					d.bizda.m++;
				} else {
					d.bizda.m = 1;
					d.bizda.y++;
				}
			} else {
				if (UNLIKELY(--d.bizda.m < 1)) {
					d.bizda.m = GREG_MONTHS_P_YEAR;
					d.bizda.y--;
				}
			}
			/* get ultimo */
			bdays = __get_bdays(d.bizda.y, d.bizda.m);
			if (UNLIKELY(tgt > bdays)) {
				tgt = bdays;
			}
			/* final assignment */
			d.bizda.bd = tgt;
			break;
		default:
			break;
		}
		break;

	case DT_DURYMD:
		switch (d.typ) {
			unsigned int mdays;
		case DT_YMD:
			tgt = dur.ymd.m;
			forw = !dt_dur_neg_p(dur);

			if ((forw && d.ymd.m < tgt) ||
			    (!forw && d.ymd.m > tgt)) {
				/* no year adjustment */
				;
			} else if (d.ymd.m == tgt && !nextp) {
				/* we're IN the month already and no
				 * next/prev date is requested */
				;
			} else if (forw) {
				/* years don't wrap around */
				d.ymd.y++;
			} else {
				/* years don't wrap around */
				d.ymd.y--;
			}
			/* final assignment */
			d.ymd.m = tgt;
			/* fixup ultimo mismatches */
			mdays = __get_mdays(d.ymd.y, d.ymd.m);
			if (UNLIKELY(d.ymd.d > mdays)) {
				d.ymd.d = mdays;
			}
			break;
		default:
			break;
		}
		break;

	case DT_DURYMCW: {
		struct dt_d_s tmp;
		unsigned int wday;
		signed int diff;

		forw = !dt_dur_neg_p(dur);
		tgt = dur.ymcw.w;

		tmp = dt_dconv(DT_DAISY, d);
		wday = dt_get_wday(tmp);
		diff = (signed)tgt - (signed)wday;


		if ((forw && wday < tgt) ||
		    (!forw && wday > tgt)) {
			/* nothing to do */
			;
		} else if (wday == tgt && !nextp) {
			/* we're on WDAY already, do fuckall */
			;
		} else if (forw) {
			/* week wrap */
			diff += 7;
		} else {
			/* week wrap */
			diff -= 7;
		}

		/* final assignment */
		tmp.daisy += diff;
		d = dt_dconv(d.typ, tmp);
		break;
	}

	case DT_DURWK:
		if (dur.dv > 0) {
			tgt = dur.dv;
			forw = true;
		} else if (dur.dv < 0) {
			tgt = -dur.dv;
			forw = false;
		} else {
			/* user is an idiot */
			break;
		}

		switch (d.typ) {
			unsigned int nw;
		case DT_YWD:
			if ((forw && d.ywd.c < tgt) ||
			    (!forw && d.ywd.c > tgt)) {
				/* no year adjustment */
				;
			} else if (d.ywd.c == tgt && !nextp) {
				/* we're IN the week already and no
				 * next/prev date is requested */
				;
			} else if (forw) {
				/* years don't wrap around */
				d.ywd.y++;
			} else {
				/* years don't wrap around */
				d.ywd.y--;
			}
			/* final assignment */
			d.ywd.c = tgt;
			/* fixup ultimo mismatches */
			nw = __get_isowk(d.ywd.y);
			if (UNLIKELY(d.ywd.c > nw)) {
				d.ywd.c = nw;
			}
			break;
		default:
			break;
		}
		break;

	default:
		break;
	}
	return d;
}