caddr_t bif_dateadd (caddr_t * qst, caddr_t * err_ret, state_slot_t ** args) { caddr_t res; caddr_t part = bif_string_arg (qst, args, 0, "dateadd"); boxint n = bif_long_arg (qst, args, 1, "dateadd"); caddr_t dt = bif_date_arg (qst, args, 2, "dateadd"); TIMESTAMP_STRUCT ts; int dt_type = DT_DT_TYPE (dt); int year_or_month_tz_tweak = (((!strcmp ("year", part)) || (!strcmp ("month", part))) ? DT_TZ (dt) : 0); DT_AUDIT_FIELDS (dt); dt_to_GMTimestamp_struct (dt, &ts); if (year_or_month_tz_tweak) ts_add (&ts, year_or_month_tz_tweak, "minute"); ts_add (&ts, n, part); if (year_or_month_tz_tweak) ts_add (&ts, -year_or_month_tz_tweak, "minute"); res = dk_alloc_box (DT_LENGTH, DV_DATETIME); GMTimestamp_struct_to_dt (&ts, res); DT_SET_TZ (res, DT_TZ (dt)); if (DT_TYPE_DATE == dt_type && (0 == stricmp (part, "year") || 0 == stricmp (part, "month") || 0 == stricmp (part, "day"))) DT_SET_DT_TYPE (res, dt_type); DT_AUDIT_FIELDS (dt); return res; }
caddr_t bif_dt_set_tz (caddr_t * qst, caddr_t * err_ret, state_slot_t ** args) { caddr_t arg = bif_date_arg (qst, args, 0, "dt_set_tz"); long tz = (long) bif_long_arg (qst, args, 1, "dt_set_tz"); caddr_t res = box_copy (arg); DT_SET_TZ (res, tz); return res; }
caddr_t bif_date_string_GMT (caddr_t * qst, caddr_t * err_ret, state_slot_t ** args) { char temp[100]; caddr_t arg = bif_date_arg (qst, args, 0, "datestring"); char dt2[DT_LENGTH]; memcpy (dt2, arg, DT_LENGTH); DT_SET_TZ (dt2, 0); dt_to_string (dt2, temp, sizeof (temp)); return (box_dv_short_string (temp)); }
caddr_t bif_timestampadd (caddr_t * qst, caddr_t * err_ret, state_slot_t ** args) { caddr_t res; ptrlong part = bif_long_arg (qst, args, 0, "timestampadd"); int n = (int) bif_long_arg (qst, args, 1, "timestampadd"); caddr_t dt = bif_date_arg (qst, args, 2, "timestampadd"); int saved_tz = DT_TZ (dt); GMTIMESTAMP_STRUCT ts; dt_to_GMTimestamp_struct (dt, &ts); ts_add (&ts, n, interval_odbc_to_text (part, "timestampadd")); res = dk_alloc_box (DT_LENGTH, DV_DATETIME); GMTimestamp_struct_to_dt (&ts, res); DT_SET_TZ (res, saved_tz); return res; }
int /* Returns number of chars parsed. */ dt_scan_from_buffer (const char *buf, int mode, caddr_t *dt_ret, const char **err_msg_ret) { const char *tail = buf; int fld_len, acc, ymd_found = 0, hms_found = 0, msec_factor; TIMESTAMP_STRUCT ts; memset (&ts, 0, sizeof (TIMESTAMP_STRUCT)); dt_ret[0] = NULL; err_msg_ret[0] = NULL; fld_len = 0; acc = 0; while (isdigit (tail[0]) && (4 > fld_len)) { acc = acc * 10 + (tail++)[0] - '0'; fld_len++; } if ('-' == tail[0]) { /* Date delimiter, let's parse date part */ if (((DT_PRINT_MODE_YMD | DT_PRINT_MODE_HMS) & mode) && !(DT_PRINT_MODE_YMD & mode)) { err_msg_ret[0] = "Time field is expected but date field delimiter is found"; return 0; } if (4 != fld_len) { err_msg_ret[0] = "Year field should have 4 digits"; return 0; } ymd_found = 1; ts.year = acc; tail++; fld_len = 0; acc = 0; while (isdigit (tail[0]) && (2 > fld_len)) { acc = acc * 10 + (tail++)[0] - '0'; fld_len++; } if (2 != fld_len) { err_msg_ret[0] = "Month field should have 2 digits"; return 0; } if ('-' != tail[0]) { err_msg_ret[0] = "Minus sign is expected after month"; return 0; } ts.month = acc; tail++; fld_len = 0; acc = 0; while (isdigit (tail[0]) && (2 > fld_len)) { acc = acc * 10 + (tail++)[0] - '0'; fld_len++; } if (2 != fld_len) { err_msg_ret[0] = "Day of month field should have 2 digits"; return 0; } ts.day = acc; if ('T' != tail[0]) goto scan_tz; /* see below */ tail++; fld_len = 0; acc = 0; while (isdigit (tail[0]) && (2 > fld_len)) { acc = acc * 10 + (tail++)[0] - '0'; fld_len++; } } if (':' == tail[0]) { /* Time delimiter, let's parse time part */ if (((DT_PRINT_MODE_YMD | DT_PRINT_MODE_HMS) & mode) && !(DT_PRINT_MODE_HMS & mode)) { err_msg_ret[0] = "Date field is expected but time field delimiter is found"; return 0; } if (2 != fld_len) { err_msg_ret[0] = "Hour field should have 2 digits"; return 0; } hms_found = 1; ts.hour = acc; tail++; fld_len = 0; acc = 0; while (isdigit (tail[0]) && (2 > fld_len)) { acc = acc * 10 + (tail++)[0] - '0'; fld_len++; } if (2 != fld_len) { err_msg_ret[0] = "Minute field should have 2 digits"; return 0; } if (':' != tail[0]) { err_msg_ret[0] = "Colon is expected after minute"; return 0; } ts.minute = acc; tail++; fld_len = 0; acc = 0; while (isdigit (tail[0]) && (2 > fld_len)) { acc = acc * 10 + (tail++)[0] - '0'; fld_len++; } if (2 != fld_len) { err_msg_ret[0] = "Second field should have 2 digits"; return 0; } ts.second = acc; if ('.' == tail[0]) { tail++; msec_factor = 1000000000; acc = 0; if (!isdigit (tail[0])) { err_msg_ret[0] = "Fraction of second is expected after decimal dot"; return 0; } do { if (msec_factor) acc = acc * 10 + (tail[0] - '0'); tail++; msec_factor /= 10; } while (isdigit (tail[0])); ts.fraction = acc * (msec_factor ? msec_factor : 1); } if ('Z' != tail[0] && strncmp (tail, " GMT", 4)) { err_msg_ret[0] = "Colon or time zone is expected after minute"; return 0; } } else { err_msg_ret[0] = "Generic syntax error in date/time"; return 0; } scan_tz: /* Now HMS part is complete (or skipped) */ if ('Z' == tail[0]) tail++; else if (!strncmp (tail, " GMT", 4)) tail += 4; else { err_msg_ret[0] = "Generic syntax error in date/time"; return 0; } if ((DT_PRINT_MODE_YMD & mode) && !ymd_found) { err_msg_ret[0] = "Datetime expected but time-only string is found"; return 0; } if ((DT_PRINT_MODE_HMS & mode) && !hms_found) { err_msg_ret[0] = "Datetime expected but date-only string is found"; return 0; } dt_ret[0] = dk_alloc_box (DT_LENGTH, DV_DATETIME); { uint32 day; day = date2num (ts.year, ts.month, ts.day); DT_SET_DAY (dt_ret[0], day); DT_SET_HOUR (dt_ret[0], ts.hour); DT_SET_MINUTE (dt_ret[0], ts.minute); DT_SET_SECOND (dt_ret[0], ts.second); DT_SET_FRACTION (dt_ret[0], ts.fraction); DT_SET_TZ (dt_ret[0], dt_local_tz); } SET_DT_TYPE_BY_DTP (dt_ret[0], (ymd_found ? (hms_found ? DV_DATETIME : DV_DATE) : DV_TIME)); return (tail - buf); }
caddr_t arithm_dt_add_num (ccaddr_t box1, ccaddr_t box2, int subtraction, caddr_t *err_ret) { int dt_type = DT_DT_TYPE (box1); dtp_t dtp2 = DV_TYPE_OF (box2); boxint whole_seconds = 0; boxint nanoseconds = 0; TIMESTAMP_STRUCT ts; caddr_t res; switch (dtp2) { case DV_LONG_INT: whole_seconds = unbox (box2); break; case DV_DOUBLE_FLOAT: { double n = unbox_double (box2); double rest; whole_seconds = (n >= 0.0) ? floor(n + 0.5) : ceil(n - 0.5); rest = n - whole_seconds; if (abs(rest/n) > (3 * DBL_EPSILON)) nanoseconds = (n - whole_seconds) * 1000000000L; break; } case DV_NUMERIC: { numeric_t n = (numeric_t)box2; if (NUMERIC_STS_SUCCESS != numeric_to_int64 (n, &whole_seconds)) { err_ret[0] = srv_make_new_error ("22003", "SR087", "Wrong arguments for datetime arithmetic: decimal is out of range."); return NULL; } if (n->n_scale > 0) { char *nptr = n->n_value + n->n_len; int ctr; int mult = 1; for (ctr = 9; ctr > n->n_scale; ctr--) mult *= 10; while (ctr--) { nanoseconds += mult * nptr[ctr]; mult *= 10; } } break; } default: return NULL; } DT_AUDIT_FIELDS (dt); dt_to_GMTimestamp_struct (box1, &ts); ts_add (&ts, (subtraction ? -whole_seconds : whole_seconds), "second"); if (nanoseconds) ts_add (&ts, (subtraction ? -nanoseconds : nanoseconds), "nanosecond"); res = dk_alloc_box (DT_LENGTH, DV_DATETIME); GMTimestamp_struct_to_dt (&ts, res); DT_SET_TZ (res, DT_TZ (box1)); if ((DT_TYPE_DATE == dt_type) && (0 == (((whole_seconds * 1000000000L) + nanoseconds) % (SPERDAY * 1000000000L)))) DT_SET_DT_TYPE (res, dt_type); DT_AUDIT_FIELDS (dt); return res; }