static int dt_add_dt(void) { static const char str[] = "2012-03-28T23:55:55"; struct dt_dt_s d; struct dt_dt_s dur; int res = 0; fprintf(stderr, "testing %s +1d1h ...\n", str); d = dt_strpdt(str, NULL, NULL); /* we lack some lovely ctors for this */ dur = dt_dt_initialiser(); dt_make_sandwich(&dur, DT_DAISY, DT_TUNK); dur.dur = 1; dur.neg = 0; dur.d.daisy = 1; dur.t.dur = 1; dur.t.neg = 0; dur.t.sdur = 3600; /* the actual addition */ d = dt_dtadd(d, dur); CHECK(d.d.typ != DT_YMD, " DATE TYPE DIFFERS %u ... should be %u\n", (unsigned int)d.d.typ, (unsigned int)DT_YMD); CHECK(d.t.typ != DT_HMS, " TIME TYPE DIFFERS %u ... should be %u\n", (unsigned int)d.t.typ, (unsigned int)DT_HMS); CHECK(d.dur, " DURATION BIT SET\n"); CHECK(d.neg, " NEGATED BIT SET\n"); CHECK(d.t.dur, " TIME DURATION BIT SET\n"); CHECK(d.t.neg, " TIME NEGATED BIT SET\n"); CHECK_EQ((unsigned int)d.d.ymd.y, 2012U, " YEAR %u ... should be %u\n"); CHECK_EQ((unsigned int)d.d.ymd.m, 3U, " MONTH %u ... should be %u\n"); CHECK_EQ((unsigned int)d.d.ymd.d, 30U, " DAY %u ... should be %u\n"); CHECK_EQ((unsigned int)d.t.hms.h, 00U, " HOUR %u ... should be %u\n"); CHECK_EQ((unsigned int)d.t.hms.m, 55U, " MINUTE %u ... should be %u\n"); CHECK_EQ((unsigned int)d.t.hms.s, 55U, " SECOND %u ... should be %u\n"); /* make sure the padding leaves no garbage */ CHECK_RES(res, d.d.ymd.u & ~0x1fffff, " PADDING NOT NAUGHT %x\n", (unsigned int)(d.d.ymd.u & ~0x1fffff)); CHECK_RES(res, d.t.hms.u & ~0x1f3f3f3fffffff, " TIME PADDING NOT NAUGHT %x\n", (unsigned int)(d.t.hms.u & ~0x1f3f3f3fffffff)); return res; }
/** * 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 struct dt_dt_s __fixup_zdiff(struct dt_dt_s dt, int32_t zdiff) { /* apply time zone difference */ struct dt_dt_s zd = dt_dt_initialiser(); dt_make_t_only(&zd, DT_HMS); zd.t.dur = 1; zd.t.sdur = -zdiff; /* reuse dt for result */ dt = dt_dtadd(dt, zd); dt.znfxd = 1; return dt; }
static inline struct dt_dt_s dt_conv_to_sexy(struct dt_dt_s dt) { if (dt.typ == DT_SEXY) { return dt; } else if (dt_sandwich_only_t_p(dt)) { dt.sxepoch = (dt.t.hms.h * 60 + dt.t.hms.m) * 60 + dt.t.hms.s; } else if (dt_sandwich_p(dt) || dt_sandwich_only_d_p(dt)) { dt.sxepoch = __to_unix_epoch(dt); } else { dt = dt_dt_initialiser(); } /* make sure we hand out sexies */ dt.typ = DT_SEXY; return dt; }
static inline struct dt_dt_s __ymdhms_to_ymd(dt_ymdhms_t x) { struct dt_dt_s res = dt_dt_initialiser(); res.t.hms.s = x.S; res.t.hms.m = x.M; res.t.hms.h = x.H; /* rest is a day-count, move to daisy */ res.d.ymd.y = x.y; res.d.ymd.m = x.m; res.d.ymd.d = x.d; /* sandwichify */ dt_make_sandwich(&res, DT_YMD, DT_HMS); return res; }
static inline struct dt_dt_s __sexy_to_daisy(dt_ssexy_t sx) { struct dt_dt_s res = dt_dt_initialiser(); res.t.hms.s = sx % SECS_PER_MIN; sx /= SECS_PER_MIN; res.t.hms.m = sx % MINS_PER_HOUR; sx /= MINS_PER_HOUR; res.t.hms.h = sx % HOURS_PER_DAY; sx /= HOURS_PER_DAY; /* rest is a day-count, move to daisy */ res.d.daisy = sx + DAISY_UNIX_BASE; /* sandwichify */ dt_make_sandwich(&res, DT_DAISY, DT_HMS); return res; }
DEFUN struct dt_dt_s __strpdt_std(const char *str, char **ep) { /* code dupe, see __strpd_std() */ struct dt_dt_s res = dt_dt_initialiser(); struct strpdt_s d = strpdt_initialiser(); const char *sp; if ((sp = str) == NULL) { goto out; } /* check for epoch notation */ if (*sp == '@') { /* yay, epoch */ const char *tmp; d.i = strtoi(++sp, &tmp); if (UNLIKELY(d.i == -1 && sp == tmp)) { sp--; } else { /* let's make a DT_SEXY */ res.typ = DT_SEXY; res.sxepoch = d.i; } goto out; } /* read the year */ if ((d.sd.y = strtoi_lim(sp, &sp, DT_MIN_YEAR, DT_MAX_YEAR)) < 0 || *sp++ != '-') { sp = str; goto try_time; } /* check for ywd dates */ if (UNLIKELY(*sp == 'W')) { /* brilliant */ if ((sp++, d.sd.c = strtoi_lim(sp, &sp, 0, 53)) < 0 || *sp++ != '-') { goto try_time; } d.sd.flags.c_wcnt_p = 1; d.sd.flags.wk_cnt = YWD_ISOWK_CNT; goto dow; } /* read the month */ if ((d.sd.m = strtoi_lim(sp, &sp, 0, 12)) < 0 || *sp++ != '-') { sp = str; goto out; } /* read the day or the count */ if ((d.sd.d = strtoi_lim(sp, &sp, 0, 31)) < 0) { /* didn't work, f**k off */ sp = str; goto out; } /* check the date type */ switch (*sp) { case '-': /* it is a YMCW date */ if ((d.sd.c = d.sd.d) > 5) { /* nope, it was bollocks */ break; } d.sd.d = 0; dow: if ((d.sd.w = strtoi_lim(++sp, &sp, 0, 7)) < 0) { /* didn't work, f**k off */ sp = str; goto out; } /* fix up d.sd.w right away */ d.sd.w = d.sd.w ?: DT_SUNDAY; break; case 'B': /* it's a bizda/YMDU before ultimo date */ d.sd.flags.ab = BIZDA_BEFORE; case 'b': /* it's a bizda/YMDU after ultimo date */ d.sd.flags.bizda = 1; d.sd.b = d.sd.d; d.sd.d = 0; sp++; break; default: /* we don't care */ break; } /* guess what we're doing */ if ((res.d = __guess_dtyp(d.sd)).typ == DT_DUNK) { /* not much use parsing on */ goto out; } /* check for the d/t separator */ switch (*sp) { case 'T': case ' ': case '\t': /* could be a time, could be something, else * make sure we leave a mark */ str = sp++; break; default: /* should be a no-op */ dt_make_d_only(&res, res.d.typ); goto out; } try_time: /* and now parse the time */ if ((d.st.h = strtoi_lim(sp, &sp, 0, 23)) < 0) { sp = str; goto out; } else if (*sp != ':') { goto eval_time; } else if ((d.st.m = strtoi_lim(++sp, &sp, 0, 59)) < 0) { d.st.m = 0; goto eval_time; } else if (*sp != ':') { goto eval_time; } else if ((d.st.s = strtoi_lim(++sp, &sp, 0, 60)) < 0) { d.st.s = 0; } else if (*sp != '.') { goto eval_time; } else if ((d.st.ns = strtoi_lim(++sp, &sp, 0, 999999999)) < 0) { d.st.ns = 0; goto eval_time; } eval_time: res.t.hms.h = d.st.h; res.t.hms.m = d.st.m; res.t.hms.s = d.st.s; if (res.d.typ > DT_DUNK) { const char *tp; dt_make_sandwich(&res, res.d.typ, DT_HMS); /* check for the zone stuff */ if ((d.zdiff = try_zone(sp, &tp))) { res = __fixup_zdiff(res, d.zdiff); } else if (tp > sp) { res.znfxd = 1U; } sp = tp; } else { dt_make_t_only(&res, DT_HMS); } out: /* res.typ coincides with DT_SANDWICH_D_ONLY() if we jumped here */ if (ep != NULL) { *ep = (char*)sp; } return res; }