/* * Copyright (C) 1995. Bill Brown & Michael Shapiro * * This program is free software under the GPL (>=v2) * Read the file GPL.TXT coming with GRASS for details. */ #include static void make_incr(); /*! * \brief * * Changes the from/to of the type for dt. * The 'from/to' must be legal * values for the mode of dt; (if they are not legal, then the original values * are preserved, dt is not changed). * Returns: * 0 OK * -1 invalid 'dt' * -2 invalid 'from/to'
* * \param dt * \param from * \param to * \param round * \return int */ int datetime_change_from_to(DateTime * dt, int from, int to, int round) { DateTime dummy, incr; int pos; int carry; int ndays; int dtfrom; /* is 'dt' valid? */ if (!datetime_is_valid_type(dt)) return -1; /* is new from/to valid for dt->mode? */ if (datetime_set_type(&dummy, dt->mode, from, to, 0) != 0) return -2; /* copy dt->from to local variable, then change it in the structure so that increment works correctly for RELATIVE. Otherwise, since increment "reduces" answers, performing carries, we would carry to invalid units */ dtfrom = dt->from; /* now set the from */ dt->from = from; /* convert the "lost" lower elements to equiv value for the new 'from' * NOTE: this only affects DATETIME_RELATIVE * since absolute will have from==dt->from==YEAR */ for (pos = dtfrom; pos < from; pos++) { switch (pos) { case DATETIME_YEAR: dt->month += dt->year * 12; dt->year = 0; break; case DATETIME_DAY: dt->hour += dt->day * 24; dt->day = 0; break; case DATETIME_HOUR: dt->minute += dt->hour * 60; dt->hour = 0; break; case DATETIME_MINUTE: dt->second += dt->minute * 60.0; dt->minute = 0; break; } } /* if losing precision, round * round > 0 force up if any lost values not zero * round ==0 increment by all lost values */ if (to < dt->to) { if (round > 0) { int x; x = datetime_is_absolute(dt) ? 1 : 0; for (carry = 0, pos = dt->to; carry == 0 && pos > to; pos--) { switch (pos) { case DATETIME_MONTH: if (dt->month != x) carry = 1; break; case DATETIME_DAY: if (dt->day != x) carry = 1; break; case DATETIME_HOUR: if (dt->hour != 0) carry = 1; break; case DATETIME_MINUTE: if (dt->minute != 0) carry = 1; break; case DATETIME_SECOND: if (dt->second != 0) carry = 1; break; } } if (carry) { make_incr(&incr, to, to, dt); incr.year = 1; incr.month = 1; incr.day = 1; incr.hour = 1; incr.minute = 1; incr.second = 1.0; datetime_increment(dt, &incr); } } if (round == 0) { /*NEW*/ if (datetime_is_absolute(dt)) /*NEW*/ ndays = datetime_days_in_year(dt->year, dt->positive); /*NEW*/ else /*NEW*/ ndays = 0; for (pos = dt->to; pos > to; pos--) { make_incr(&incr, pos, pos, dt); incr.year = dt->year; incr.month = dt->month; /*NEW*/ incr.day = dt->day + ndays / 2; incr.hour = dt->hour; incr.minute = dt->minute; incr.second = dt->second; datetime_increment(dt, &incr); /*NEW*/ if (ndays > 0 && pos == DATETIME_DAY) /*NEW*/ break; } } } /* set the new elements to zero */ for (pos = from; pos < dtfrom; pos++) switch (pos) { case DATETIME_YEAR: dt->year = 0; break; case DATETIME_MONTH: dt->month = 0; break; case DATETIME_DAY: dt->day = 0; break; case DATETIME_HOUR: dt->hour = 0; break; case DATETIME_MINUTE: dt->minute = 0; break; case DATETIME_SECOND: dt->second = 0; break; } for (pos = to; pos > dt->to; pos--) switch (pos) { case DATETIME_YEAR: dt->year = 0; break; case DATETIME_MONTH: dt->month = 0; break; case DATETIME_DAY: dt->day = 0; break; case DATETIME_HOUR: dt->hour = 0; break; case DATETIME_MINUTE: dt->minute = 0; break; case DATETIME_SECOND: dt->second = 0; break; } /* make sure that fracsec is zero if original didn't have seconds */ if (dt->to < DATETIME_SECOND) dt->fracsec = 0; /* now set the to */ dt->to = to; return 0; } static void make_incr(DateTime * incr, int from, int to, DateTime * dt) { datetime_set_type(incr, DATETIME_RELATIVE, from, to, 0); if (datetime_is_relative(dt) && datetime_is_negative(dt)) datetime_set_negative(incr); }