GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-9aacb948ba
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 
54 int datetime_change_from_to(DateTime *dt, int from, int to, int round)
55 {
56  DateTime dummy, incr;
57  int pos;
58  int carry;
59  int ndays;
60  int dtfrom;
61 
62  /* is 'dt' valid? */
63  if (!datetime_is_valid_type(dt))
64  return -1;
65 
66  /* is new from/to valid for dt->mode? */
67  if (datetime_set_type(&dummy, dt->mode, from, to, 0) != 0)
68  return -2;
69 
70  /* copy dt->from to local variable, then change it
71  in the structure so that increment works correctly for RELATIVE.
72  Otherwise, since increment "reduces" answers, performing carries,
73  we would carry to invalid units */
74 
75  dtfrom = dt->from;
76 
77  /* now set the from */
78  dt->from = from;
79 
80  /* convert the "lost" lower elements to equiv value for the new 'from'
81  * NOTE: this only affects DATETIME_RELATIVE
82  * since absolute will have from==dt->from==YEAR
83  */
84  for (pos = dtfrom; pos < from; pos++) {
85  switch (pos) {
86  case DATETIME_YEAR:
87  dt->month += dt->year * 12;
88  dt->year = 0;
89  break;
90  case DATETIME_DAY:
91  dt->hour += dt->day * 24;
92  dt->day = 0;
93  break;
94  case DATETIME_HOUR:
95  dt->minute += dt->hour * 60;
96  dt->hour = 0;
97  break;
98  case DATETIME_MINUTE:
99  dt->second += dt->minute * 60.0;
100  dt->minute = 0;
101  break;
102  }
103  }
104 
105  /* if losing precision, round
106  * round > 0 force up if any lost values not zero
107  * round ==0 increment by all lost values
108  */
109  if (to < dt->to) {
110  if (round > 0) {
111  int x;
112 
113  x = datetime_is_absolute(dt) ? 1 : 0;
114 
115  for (carry = 0, pos = dt->to; carry == 0 && pos > to; pos--) {
116  switch (pos) {
117  case DATETIME_MONTH:
118  if (dt->month != x)
119  carry = 1;
120  break;
121  case DATETIME_DAY:
122  if (dt->day != x)
123  carry = 1;
124  break;
125  case DATETIME_HOUR:
126  if (dt->hour != 0)
127  carry = 1;
128  break;
129  case DATETIME_MINUTE:
130  if (dt->minute != 0)
131  carry = 1;
132  break;
133  case DATETIME_SECOND:
134  if (dt->second != 0)
135  carry = 1;
136  break;
137  }
138  }
139 
140  if (carry) {
141  make_incr(&incr, to, to, dt);
142 
143  incr.year = 1;
144  incr.month = 1;
145  incr.day = 1;
146  incr.hour = 1;
147  incr.minute = 1;
148  incr.second = 1.0;
149 
150  datetime_increment(dt, &incr);
151  }
152  }
153 
154  if (round == 0) {
155  /*NEW*/ if (datetime_is_absolute(dt))
156  /*NEW*/ ndays = datetime_days_in_year(dt->year, dt->positive);
157  /*NEW*/
158  else
159  /*NEW*/ ndays = 0;
160 
161  for (pos = dt->to; pos > to; pos--) {
162  make_incr(&incr, pos, pos, dt);
163 
164  incr.year = dt->year;
165  incr.month = dt->month;
166  /*NEW*/ incr.day = dt->day + ndays / 2;
167  incr.hour = dt->hour;
168  incr.minute = dt->minute;
169  incr.second = dt->second;
170 
171  datetime_increment(dt, &incr);
172  /*NEW*/ if (ndays > 0 && pos == DATETIME_DAY)
173  /*NEW*/ break;
174  }
175  }
176  }
177 
178  /* set the new elements to zero */
179  for (pos = from; pos < dtfrom; pos++)
180  switch (pos) {
181  case DATETIME_YEAR:
182  dt->year = 0;
183  break;
184  case DATETIME_MONTH:
185  dt->month = 0;
186  break;
187  case DATETIME_DAY:
188  dt->day = 0;
189  break;
190  case DATETIME_HOUR:
191  dt->hour = 0;
192  break;
193  case DATETIME_MINUTE:
194  dt->minute = 0;
195  break;
196  case DATETIME_SECOND:
197  dt->second = 0;
198  break;
199  }
200 
201  for (pos = to; pos > dt->to; pos--)
202  switch (pos) {
203  case DATETIME_YEAR:
204  dt->year = 0;
205  break;
206  case DATETIME_MONTH:
207  dt->month = 0;
208  break;
209  case DATETIME_DAY:
210  dt->day = 0;
211  break;
212  case DATETIME_HOUR:
213  dt->hour = 0;
214  break;
215  case DATETIME_MINUTE:
216  dt->minute = 0;
217  break;
218  case DATETIME_SECOND:
219  dt->second = 0;
220  break;
221  }
222 
223  /* make sure that fracsec is zero if original didn't have seconds */
224  if (dt->to < DATETIME_SECOND)
225  dt->fracsec = 0;
226 
227  /* now set the to */
228  dt->to = to;
229 
230  return 0;
231 }
232 
233 static void make_incr(DateTime *incr, int from, int to, DateTime *dt)
234 {
235  datetime_set_type(incr, DATETIME_RELATIVE, from, to, 0);
237  datetime_set_negative(incr);
238 }
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:54
#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:36
void datetime_set_negative(DateTime *dt)
Makes the DateTime negative. (B.C. for ABSOLUTE DateTimes)
Definition: sign.c:64
int datetime_is_valid_type(const DateTime *dt)
Returns: 1 if datetime_check_type() returns 0 0 if not.
Definition: datetime/type.c:77
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:68
int datetime_days_in_year(int year, int ad)
returns the number of days in 'year'
Definition: datetime/misc.c:39
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