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