/** * Return a dt object that forgot about DT's zone and uses ZONE instead. */ DEFUN struct dt_dt_s dtz_forgetz(struct dt_dt_s d, zif_t zone) { struct dt_dt_s res; dt_ssexy_t d_unix; if (dt_sandwich_only_d_p(d) || dt_sandwich_only_t_p(d)) { return d; } /* convert date/time part to unix stamp */ d_unix = ____to_unix_epoch(d); d_unix = zif_utc_time(zone, d_unix); /* convert the date part back */ if (d.typ > (dt_dttyp_t)DT_DUNK && d.typ < (dt_dttyp_t)DT_NDTYP) { int32_t sexy = __pos_mod(d_unix, 86400); /* temporarily go daisy */ res.d.typ = DT_DAISY; res.d.daisy = d_unix / 86400 + DAISY_UNIX_BASE; res.d = dt_dconv(d.d.typ, res.d); /* set the other flags too */ res.sandwich = d.sandwich; res.dur = 0; res.neg = 0; /* convert the time part back */ res.t.hms.s = sexy % 60; res.t.hms.m = (sexy % 3600) / 60; res.t.hms.h = sexy / 3600; res.t.hms.ns = d.t.hms.ns; res.t.typ = DT_HMS; res.t.dur = 0; res.t.neg = 0; res.t.carry = 0; } else if (d.typ == DT_SEXY) { res.typ = DT_SEXY; res.sandwich = 0; res.dur = 0; res.neg = 0; res.sxepoch = d_unix; } else { res = dt_dt_initialiser(); } return res; }
static inline dt_ssexy_t ____to_unix_epoch(struct dt_dt_s dt) { /* daisy is competing with the prevalent unix epoch, this is the offset */ #define DAISY_UNIX_BASE (19359) if (dt.typ == DT_SEXY) { /* no way to find out, is there */ return dt.sexy; } else if (dt_sandwich_p(dt) || dt_sandwich_only_d_p(dt)) { struct dt_d_s d = dt_dconv(DT_DAISY, dt.d); dt_daisy_t dd = d.daisy; dt_ssexy_t res = (dd - DAISY_UNIX_BASE) * SECS_PER_DAY; if (dt_sandwich_p(dt)) { res += (dt.t.hms.h * 60 + dt.t.hms.m) * 60 + dt.t.hms.s; } return res; } return 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; }