123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- /*
- * Copyright (C) 1995. Bill Brown <brown@gis.uiuc.edu> & Michael Shapiro
- *
- * This program is free software under the GPL (>=v2)
- * Read the file GPL.TXT coming with GRASS for details.
- */
- #include <grass/datetime.h>
- 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' <br>
- <ul>
- <li> round =
- * negative implies floor() [decrease magnitude]
- * 0 implies normal rounding, [incr/decr magnitude]
- * positive implies ceil() [increase magnitude]
- </li>
- <li> If dt.from < 'from' (losing "lower" elements), convert the "lost"
- * values to the equivalent value for the new 'from' Lost elements are then set
- * to zero. (This case can only occur for dt.mode relative):
- * months += lost years * 12 ; years = 0
- * hours += lost days * 24 ; days = 0
- * minutes += lost hours * 60 ; hours = 0
- * seconds += lost minutes * 60.0 ; minutes = 0
- </li>
- <li> If dt.from > 'from' (adding "lower" elements), the new elements are set
- * to zero.
- </li>
- <li> If dt.to < 'to' (adding "higher" elements), the new elements are set to
- * zero.
- </li>
- <li> If dt.to > 'to' (losing "higher" elements), the the new 'to' is
- * adjusted according to the value for 'round' After rounding the "lost"
- * elements are set to zero.
- </li></ul>
- *
- * \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);
- }
|