caddr_t bif_week (caddr_t * qst, caddr_t * err_ret, state_slot_t ** args) { caddr_t arg = bif_date_arg (qst, args, 0, "week"); TIMESTAMP_STRUCT ts; uint32 nowadays, new_year; dt_to_timestamp_struct (arg, &ts); nowadays = date2num (ts.year, ts.month, ts.day); new_year = date2num (ts.year, 1, 1); return (box_num ((nowadays - new_year) / 7 + 1)); }
/****************************************************************************** * @brief Initialize global time origin *****************************************************************************/ void initialize_time() { extern global_param_struct global_param; dmy_struct dmy; // Origin is 0001-01-01 dmy.year = 1; dmy.month = 1; dmy.day = 1; dmy.day_in_year = 1; dmy.dayseconds = 0; // Set origin using date2num with numeric origin of 0. // This calculates the julian day (in units of days) // for 0001-01-01 for the given calendar // This is later used as the reference (origin for advancing numeric dates). // See make_dmy.c for more details on how global_param.time_origin_num is used. global_param.time_origin_num = date2num(0., &dmy, 0., global_param.calendar, TIME_UNITS_DAYS); // Set the string representation of time_origin_num strcpy(global_param.time_origin_str, "0001-01-01 00:00:00"); return; }
static int dayofweek (caddr_t arg) { TIMESTAMP_STRUCT ts; uint32 nowadays, easter_sunday = date2num (2000, 4, 30); dt_to_timestamp_struct (arg, &ts); nowadays = date2num (ts.year, ts.month, ts.day); if (nowadays >= easter_sunday) return ((nowadays - easter_sunday) % 7 + 1); else { int wday_to_be = (easter_sunday - nowadays) % 7; return (!wday_to_be ? 1 : 8 - wday_to_be); } }
/****************************************************************************** * @brief Determine timestep and start year, month, day, and seconds of forcing files *****************************************************************************/ void get_forcing_file_info(param_set_struct *param_set, size_t file_num) { extern global_param_struct global_param; extern filenames_struct filenames; double nc_times[2]; double nc_time_origin; size_t start = 0; size_t count = 2; char *nc_unit_chars = NULL; char *calendar_char = NULL; unsigned short int time_units; unsigned short int calendar; dmy_struct nc_origin_dmy; dmy_struct nc_start_dmy; // read time info from netcdf file get_nc_field_double(filenames.forcing[0], "time", &start, &count, nc_times); get_nc_var_attr(filenames.forcing[0], "time", "units", &nc_unit_chars); get_nc_var_attr(filenames.forcing[0], "time", "calendar", &calendar_char); // parse the calendar string and check to make sure it matches the global clock calendar = str_to_calendar(calendar_char); // parse the time units parse_nc_time_units(nc_unit_chars, &time_units, &nc_origin_dmy); // Get date/time of the first entry in the forcing file. nc_time_origin = date2num(0., &nc_origin_dmy, 0., calendar, TIME_UNITS_DAYS); num2date(nc_time_origin, nc_times[0], 0., calendar, time_units, &nc_start_dmy); // Assign file start date/time global_param.forceyear[file_num] = nc_start_dmy.year; global_param.forcemonth[file_num] = nc_start_dmy.month; global_param.forceday[file_num] = nc_start_dmy.day; global_param.forcesec[file_num] = nc_start_dmy.dayseconds; // calculate timestep in forcing file if (time_units == TIME_UNITS_DAYS) { param_set->force_steps_per_day[file_num] = (size_t) nearbyint(1. / (nc_times[1] - nc_times[0])); } else if (time_units == TIME_UNITS_HOURS) { param_set->force_steps_per_day[file_num] = (size_t) nearbyint(HOURS_PER_DAY / (nc_times[1] - nc_times[0])); } else if (time_units == TIME_UNITS_MINUTES) { param_set->force_steps_per_day[file_num] = (size_t) nearbyint(MIN_PER_DAY / (nc_times[1] - nc_times[0])); } else if (time_units == TIME_UNITS_SECONDS) { param_set->force_steps_per_day[file_num] = (size_t) nearbyint(SEC_PER_DAY / (nc_times[1] - nc_times[0])); } // check that this forcing file will work if (param_set->force_steps_per_day[file_num] != global_param.model_steps_per_day) { log_err("Forcing file timestep must match the model timestep. " "Model timesteps per day is set to %zu and the forcing file " "timestep is set to %zu", global_param.model_steps_per_day, param_set->force_steps_per_day[file_num]) } if (calendar != global_param.calendar) { log_err("Calendar in forcing file (%s) does not match the calendar of " "VIC's clock", calendar_char); } // Free attribute character arrays free(nc_unit_chars); free(calendar_char); }
/****************************************************************************** * @brief This function calculates the time_delta in days from a frequency and number of steps. *****************************************************************************/ double time_delta(dmy_struct *dmy_current, unsigned short int freq, int n) { extern global_param_struct global_param; double td, a, b; dmy_struct dmy_next; unsigned short int lastday[MONTHS_PER_YEAR]; int i; // uniform timedeltas if (freq == FREQ_NSECONDS) { td = (double) n / (double) SEC_PER_DAY; } else if (freq == FREQ_NMINUTES) { td = (double) n / (double) MIN_PER_DAY; } else if (freq == FREQ_NHOURS) { td = (double) n / (double) HOURS_PER_DAY; } else if (freq == FREQ_NDAYS) { td = (double) n; } // non-uniform timedeltas else { if (n < 1) { log_err("Negative time delta's are not implemented yet") } // copy dmy structure dmy_next = *dmy_current; if (freq == FREQ_NMONTHS) { dmy_next.month += n; if (dmy_next.month > MONTHS_PER_YEAR) { dmy_next.month -= MONTHS_PER_YEAR; dmy_next.year += 1; } } else if (freq == FREQ_NYEARS) { // advance year dmy_next.year += n; // re-calculate day_in_year (NOTE: currently will have problem // if dmy_next.year is not leap year but date is Feb 29 !) make_lastday(global_param.calendar, dmy_next.year, lastday); dmy_next.day_in_year = 0; for ( i = 0; i < MONTHS_PER_YEAR; i++ ) { if ( (i+1) == dmy_next.month ) { dmy_next.day_in_year += dmy_next.day; break; } else { dmy_next.day_in_year += lastday[i]; } } // check if the advanced date is a valid date if (invalid_date(global_param.calendar, &dmy_next)) { log_err("VIC does not support a simulation starting from " "Feb 29 of a leap year with yearly AGGFREQ or " "HISTFREQ."); } } else { log_err("Unknown frequency found during time_delta computation"); } // Check to make sure this is a valid time if (invalid_date(global_param.calendar, &dmy_next)) { log_err("Invalid date found during time_delta computation"); } // Get ordinal representation of these times a = date2num(global_param.time_origin_num, dmy_current, 0, global_param.calendar, TIME_UNITS_DAYS); b = date2num(global_param.time_origin_num, &dmy_next, 0, global_param.calendar, TIME_UNITS_DAYS); td = b - a; } return td; }
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); }