static void normalize_struct_tm (struct tm* time) { gint year = time->tm_year + 1900; gint last_day; /* Gregorian_date throws if it gets an out-of-range year * so clamp year into gregorian_date's range. */ if (year < 1400) year += 1400; if (year > 9999) year %= 10000; normalize_time_component (&(time->tm_sec), &(time->tm_min), 60, 0); normalize_time_component (&(time->tm_min), &(time->tm_hour), 60, 0); normalize_time_component (&(time->tm_hour), &(time->tm_mday), 24, 0); normalize_month (&(time->tm_mon), &year); // auto month_in_range = []int (int m){ return (m + 12) % 12; } while (time->tm_mday < 1) { normalize_month (&(--time->tm_mon), &year); last_day = gnc_date_get_last_mday (time->tm_mon, year); time->tm_mday += last_day; } last_day = gnc_date_get_last_mday (time->tm_mon, year); while (time->tm_mday > last_day) { time->tm_mday -= last_day; normalize_month(&(++time->tm_mon), &year); last_day = gnc_date_get_last_mday (time->tm_mon, year); } time->tm_year = year - 1900; }
static void normalize_struct_tm (struct tm* time) { gint year = time->tm_year + 1900; gint last_day; time64 secs; ++time->tm_mon; normalize_time_component (&(time->tm_sec), &(time->tm_min), 60, 0); normalize_time_component (&(time->tm_min), &(time->tm_hour), 60, 0); normalize_time_component (&(time->tm_hour), &(time->tm_mday), 24, 0); normalize_time_component (&(time->tm_mon), &year, 12, 1); while (time->tm_mday < 1) { last_day = gnc_date_get_last_mday (normalize_month (--time->tm_mon), year); time->tm_mday += last_day; normalize_time_component (&(time->tm_mon), &year, 12, 1); } last_day = gnc_date_get_last_mday (normalize_month (time->tm_mon), year); while (time->tm_mday > last_day) { ++time->tm_mon; time->tm_mday -= last_day; normalize_time_component (&(time->tm_mon), &year, 12, 1); last_day = gnc_date_get_last_mday (normalize_month (time->tm_mon), year); } time->tm_year = year - 1900; }
static time64 compute_time (const GncBillTerm *term, time64 post_date, int days) { time64 res = post_date; int day, month, year; switch (term->type) { case GNC_TERM_TYPE_DAYS: res += (SECS_PER_DAY * days); break; case GNC_TERM_TYPE_PROXIMO: compute_monthyear (term, post_date, &month, &year); day = gnc_date_get_last_mday (month - 1, year); if (days < day) day = days; res = gnc_dmy2time64 (day, month, year); break; } return res; }
/* Based on the post date and a proximo type, compute the month and * year this is due. The actual day is filled in below. * * A proximo billing term has multiple parameters: * * due day: day of the month the invoice/bill will be due * * cutoff: day of the month used to decide if the due date will be * in the next month or in the month thereafter. This can be * a negative number in which case the cutoff date is relative * to the end of the month and counting backwards. * Eg: cutoff = -3 would mean 25 in February or 28 in June * * How does it work: * Assume cutoff = 19 and due day = 20 * * * Example 1 post date = 14-06-2010 (European date format) * 14 is less than the cutoff of 19, so the due date will be in the next * month. Since the due day is set to 20, the due date will be * 20-07-2010 * * * Example 2 post date = 22-06-2010 (European date format) * 22 is more than the cutoff of 19, so the due date will be in the month * after next month. Since the due day is set to 20, the due date will be * 20-02-2010 * */ static void compute_monthyear (const GncBillTerm *term, time64 post_date, int *month, int *year) { int iday, imonth, iyear; struct tm tm; int cutoff = term->cutoff; g_return_if_fail (term->type == GNC_TERM_TYPE_PROXIMO); gnc_localtime_r (&post_date, &tm); iday = tm.tm_mday; imonth = tm.tm_mon + 1; iyear = tm.tm_year + 1900; if (cutoff <= 0) cutoff += gnc_date_get_last_mday (imonth - 1, iyear); if (iday <= cutoff) { /* We apply this to next month */ imonth++; } else { /* We apply to the following month */ imonth += 2; } if (imonth > 12) { iyear++; imonth -= 12; } if (month) *month = imonth; if (year) *year = iyear; }