change.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * Copyright (C) 1995. Bill Brown <brown@gis.uiuc.edu> & Michael Shapiro
  3. *
  4. * This program is free software under the GPL (>=v2)
  5. * Read the file GPL.TXT coming with GRASS for details.
  6. */
  7. #include <grass/datetime.h>
  8. static void make_incr();
  9. /*!
  10. * \brief
  11. *
  12. * Changes the from/to of the type for dt.
  13. * The 'from/to' must be legal
  14. * values for the mode of dt; (if they are not legal, then the original values
  15. * are preserved, dt is not changed).
  16. * Returns:
  17. * 0 OK
  18. * -1 invalid 'dt'
  19. * -2 invalid 'from/to' <br>
  20. <ul>
  21. <li> round =
  22. * negative implies floor() [decrease magnitude]
  23. * 0 implies normal rounding, [incr/decr magnitude]
  24. * positive implies ceil() [increase magnitude]
  25. </li>
  26. <li> If dt.from < 'from' (losing "lower" elements), convert the "lost"
  27. * values to the equivalent value for the new 'from' Lost elements are then set
  28. * to zero. (This case can only occur for dt.mode relative):
  29. * months += lost years * 12 ; years = 0
  30. * hours += lost days * 24 ; days = 0
  31. * minutes += lost hours * 60 ; hours = 0
  32. * seconds += lost minutes * 60.0 ; minutes = 0
  33. </li>
  34. <li> If dt.from > 'from' (adding "lower" elements), the new elements are set
  35. * to zero.
  36. </li>
  37. <li> If dt.to < 'to' (adding "higher" elements), the new elements are set to
  38. * zero.
  39. </li>
  40. <li> If dt.to > 'to' (losing "higher" elements), the the new 'to' is
  41. * adjusted according to the value for 'round' After rounding the "lost"
  42. * elements are set to zero.
  43. </li></ul>
  44. *
  45. * \param dt
  46. * \param from
  47. * \param to
  48. * \param round
  49. * \return int
  50. */
  51. int datetime_change_from_to(DateTime * dt, int from, int to, int round)
  52. {
  53. DateTime dummy, incr;
  54. int pos;
  55. int carry;
  56. int ndays;
  57. int dtfrom;
  58. /* is 'dt' valid? */
  59. if (!datetime_is_valid_type(dt))
  60. return -1;
  61. /* is new from/to valid for dt->mode? */
  62. if (datetime_set_type(&dummy, dt->mode, from, to, 0) != 0)
  63. return -2;
  64. /* copy dt->from to local variable, then change it
  65. in the structure so that increment works correctly for RELATIVE.
  66. Otherwise, since increment "reduces" answers, performing carries,
  67. we would carry to invalid units */
  68. dtfrom = dt->from;
  69. /* now set the from */
  70. dt->from = from;
  71. /* convert the "lost" lower elements to equiv value for the new 'from'
  72. * NOTE: this only affects DATETIME_RELATIVE
  73. * since absolute will have from==dt->from==YEAR
  74. */
  75. for (pos = dtfrom; pos < from; pos++) {
  76. switch (pos) {
  77. case DATETIME_YEAR:
  78. dt->month += dt->year * 12;
  79. dt->year = 0;
  80. break;
  81. case DATETIME_DAY:
  82. dt->hour += dt->day * 24;
  83. dt->day = 0;
  84. break;
  85. case DATETIME_HOUR:
  86. dt->minute += dt->hour * 60;
  87. dt->hour = 0;
  88. break;
  89. case DATETIME_MINUTE:
  90. dt->second += dt->minute * 60.0;
  91. dt->minute = 0;
  92. break;
  93. }
  94. }
  95. /* if losing precision, round
  96. * round > 0 force up if any lost values not zero
  97. * round ==0 increment by all lost values
  98. */
  99. if (to < dt->to) {
  100. if (round > 0) {
  101. int x;
  102. x = datetime_is_absolute(dt) ? 1 : 0;
  103. for (carry = 0, pos = dt->to; carry == 0 && pos > to; pos--) {
  104. switch (pos) {
  105. case DATETIME_MONTH:
  106. if (dt->month != x)
  107. carry = 1;
  108. break;
  109. case DATETIME_DAY:
  110. if (dt->day != x)
  111. carry = 1;
  112. break;
  113. case DATETIME_HOUR:
  114. if (dt->hour != 0)
  115. carry = 1;
  116. break;
  117. case DATETIME_MINUTE:
  118. if (dt->minute != 0)
  119. carry = 1;
  120. break;
  121. case DATETIME_SECOND:
  122. if (dt->second != 0)
  123. carry = 1;
  124. break;
  125. }
  126. }
  127. if (carry) {
  128. make_incr(&incr, to, to, dt);
  129. incr.year = 1;
  130. incr.month = 1;
  131. incr.day = 1;
  132. incr.hour = 1;
  133. incr.minute = 1;
  134. incr.second = 1.0;
  135. datetime_increment(dt, &incr);
  136. }
  137. }
  138. if (round == 0) {
  139. /*NEW*/ if (datetime_is_absolute(dt))
  140. /*NEW*/ ndays = datetime_days_in_year(dt->year, dt->positive);
  141. /*NEW*/
  142. else
  143. /*NEW*/ ndays = 0;
  144. for (pos = dt->to; pos > to; pos--) {
  145. make_incr(&incr, pos, pos, dt);
  146. incr.year = dt->year;
  147. incr.month = dt->month;
  148. /*NEW*/ incr.day = dt->day + ndays / 2;
  149. incr.hour = dt->hour;
  150. incr.minute = dt->minute;
  151. incr.second = dt->second;
  152. datetime_increment(dt, &incr);
  153. /*NEW*/ if (ndays > 0 && pos == DATETIME_DAY)
  154. /*NEW*/ break;
  155. }
  156. }
  157. }
  158. /* set the new elements to zero */
  159. for (pos = from; pos < dtfrom; pos++)
  160. switch (pos) {
  161. case DATETIME_YEAR:
  162. dt->year = 0;
  163. break;
  164. case DATETIME_MONTH:
  165. dt->month = 0;
  166. break;
  167. case DATETIME_DAY:
  168. dt->day = 0;
  169. break;
  170. case DATETIME_HOUR:
  171. dt->hour = 0;
  172. break;
  173. case DATETIME_MINUTE:
  174. dt->minute = 0;
  175. break;
  176. case DATETIME_SECOND:
  177. dt->second = 0;
  178. break;
  179. }
  180. for (pos = to; pos > dt->to; pos--)
  181. switch (pos) {
  182. case DATETIME_YEAR:
  183. dt->year = 0;
  184. break;
  185. case DATETIME_MONTH:
  186. dt->month = 0;
  187. break;
  188. case DATETIME_DAY:
  189. dt->day = 0;
  190. break;
  191. case DATETIME_HOUR:
  192. dt->hour = 0;
  193. break;
  194. case DATETIME_MINUTE:
  195. dt->minute = 0;
  196. break;
  197. case DATETIME_SECOND:
  198. dt->second = 0;
  199. break;
  200. }
  201. /* make sure that fracsec is zero if original didn't have seconds */
  202. if (dt->to < DATETIME_SECOND)
  203. dt->fracsec = 0;
  204. /* now set the to */
  205. dt->to = to;
  206. return 0;
  207. }
  208. static void make_incr(DateTime * incr, int from, int to, DateTime * dt)
  209. {
  210. datetime_set_type(incr, DATETIME_RELATIVE, from, to, 0);
  211. if (datetime_is_relative(dt) && datetime_is_negative(dt))
  212. datetime_set_negative(incr);
  213. }