GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
incr1.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 int _datetime_add_field(DateTime *, DateTime *, int);
10 static int _datetime_subtract_field(DateTime *, DateTime *, int);
11 
12 /*****************************************************************/
13 #if 0 /* unused */
14 static double _debug_decimal(DateTime * dt)
15 {
16  double dtdec = 0.0;
17 
18  if (dt->mode == DATETIME_RELATIVE) {
20  dtdec = dt->year + dt->month / 12.;
21  }
22  else {
23  dtdec = dt->day / 365.25 +
24  dt->hour / 8766. + dt->minute / 525960.
25  + dt->second / 31557600.;
26  }
27  }
28  if (dt->positive)
29  return (dtdec);
30  return (-dtdec);
31 }
32 #endif /* unused */
33 
34 /*****************************************************************/
35 
36 /*!
37  * \brief
38  *
39  * This function changes the 'src' date/time data based on the 'incr'
40  * The type (mode/from/to) of the 'src' can be anything.
41  * The mode of the 'incr' must be RELATIVE, and the type (mode/from/to) for
42  * 'incr' must be a valid increment for 'src'. See <b>datetime_is_valid_increment()</b>,
43  * <b>datetime_check_increment()</b>
44  * Returns:
45  * 0: OK
46  * -1: 'incr' is invalid increment for 'src'
47  * For src.mode ABSOLUTE,
48  * <ul>
49  <li> positive 'incr' moves into the future,
50  </li>
51  <li> negative 'incr' moves into the past.
52  </li>
53  <li> BC implies the year is negative, but all else is positive. Also, year==0
54  * is illegal: adding 1 year to 1[bc] gives 1[ad]
55  </li></ul>
56  * The 'fracsec' in 'src' is preserved.
57  * The 'from/to' of the 'src' is preserved.
58  * A timezone in 'src' is allowed - it's presence is ignored.
59  * NOTE: There is no datetime_decrement() To decrement, set the 'incr' negative.
60 
61  *
62  * \param src
63  * \param incr
64  * \return int
65  */
66 
68 {
69  int i, relfrom;
70  DateTime cpdt, *dt;
71 
72  if (!datetime_is_valid_increment(src, incr))
73  return datetime_error_code();
74 
75  /* special case - incrementing a relative might try to increment
76  or borrow from a "lower" field than src has,
77  so we use a copy to change from */
78 
79  if (src->mode == DATETIME_RELATIVE) {
80  datetime_copy(&cpdt, src);
83  datetime_change_from_to(&cpdt, relfrom, src->to, -1); /* min. from */
84  dt = &cpdt;
85  }
86  else
87  dt = src;
88 
89  /* need to call carry first? (just to make sure?) */
90  /*
91  fprintf (stdout,"DEBUG: INCR %.12lf %.12lf = %.12lf\n",
92  _debug_decimal(dt), _debug_decimal(incr),
93  _debug_decimal(dt)+_debug_decimal(incr));
94  */
95 
96  /* no sign change, just add */
97  if ((dt->positive && incr->positive) ||
98  (dt->mode == DATETIME_RELATIVE && !dt->positive && !incr->positive)) {
99 
100  for (i = incr->to; i >= incr->from; i--) {
101  _datetime_add_field(dt, incr, i);
102  }
103  }
104 
105  else if (!incr->positive || dt->mode == DATETIME_RELATIVE) {
106 
107  for (i = incr->to; i >= incr->from; i--) {
108  _datetime_subtract_field(dt, incr, i);
109  }
110  }
111 
112  /* now only two special cases of bc ABSOLUTE left */
113 
114  else if (!incr->positive) { /* incr is negative, dt is positive */
115 
116  for (i = incr->to; i > DATETIME_YEAR; i--) {
117  _datetime_subtract_field(dt, incr, i);
118  }
119  _datetime_add_field(dt, incr, DATETIME_YEAR);
120  }
121  else { /* incr is positive, dt is negative */
122 
123  for (i = incr->to; i > DATETIME_YEAR; i--) {
124  _datetime_add_field(dt, incr, i);
125  }
126  _datetime_subtract_field(dt, incr, DATETIME_YEAR);
127  }
128  /*
129  fprintf (stdout,"DEBUG: INCR RESULT = %.12lf\n", _debug_decimal(dt));
130  */
131  if (src->mode == DATETIME_RELATIVE) {
132  datetime_change_from_to(dt, src->from, src->to, -1);
133 
134  /* copy dt back into src to return */
135  datetime_copy(src, dt);
136  }
137 
138  return 0;
139 }
140 
141 
142 /*****************************************************************/
143 /*
144  When calling, the field must be
145  in the range of src, but this is not enforced here.
146 
147  The only thing used from the "incr" DateTime is the value of
148  the field being subtracted and the "from" & "to"
149 
150  by the time we get here, if src is RELATIVE, src->from should
151  already be minimized to allow borrowing from "lower" fields
152 
153  */
154 
155 static int _datetime_subtract_field(DateTime * src, DateTime * incr,
156  int field)
157 {
158 
159  if (src->mode == DATETIME_RELATIVE) {
160  DateTime srcinc, tinc;
161  int borrow = 0;
162 
163  datetime_copy(&tinc, src);
164  datetime_copy(&srcinc, incr);
165  switch (field) {
166  case DATETIME_SECOND:
167  /* no "-1" here - remember seconds is floating point */
168  /* might result in over borrowing, so have to check */
169  if (src->second < incr->second) {
170  if ((int)(incr->second - src->second) == (incr->second - src->second)) { /* diff is integer */
171  borrow = 1 + (incr->second - src->second - 1) / 60;
172  }
173  else
174  borrow = 1 + (incr->second - src->second) / 60;
175  src->second += borrow * 60;
176  }
177  src->second -= incr->second;
178  if (borrow) {
179  srcinc.minute = borrow;
180  _datetime_subtract_field(src, &srcinc, DATETIME_MINUTE);
181  }
182  break;
183 
184  case DATETIME_MINUTE:
185  if (src->minute < incr->minute) {
186  borrow = 1 + (incr->minute - src->minute - 1) / 60;
187  src->minute += borrow * 60;
188  }
189  src->minute -= incr->minute;
190  if (borrow) {
191  srcinc.hour = borrow;
192  _datetime_subtract_field(src, &srcinc, DATETIME_HOUR);
193  }
194  break;
195 
196  case DATETIME_HOUR:
197  if (src->hour < incr->hour) {
198  borrow = 1 + (incr->hour - src->hour - 1) / 24;
199  src->hour += borrow * 24;
200  }
201  src->hour -= incr->hour;
202  if (borrow) {
203  srcinc.day = borrow;
204  _datetime_subtract_field(src, &srcinc, DATETIME_DAY);
205  }
206  break;
207 
208  case DATETIME_DAY:
209  if (src->day < incr->day) { /* SIGN CHANGE */
210  src->day = incr->day - src->day;
212  tinc.day = 0;
213  src->hour = 0;
214  src->minute = 0;
215  src->second = 0.0;
216  datetime_increment(src, &tinc); /* no sign change */
217  }
218  else
219  src->day -= incr->day;
220  break;
221 
222  case DATETIME_MONTH:
223  if (src->month < incr->month) {
224  borrow = 1 + (incr->month - src->month - 1) / 12;
225  src->month += borrow * 12;
226  }
227  src->month -= incr->month;
228  if (borrow) {
229  srcinc.year = borrow;
230  _datetime_subtract_field(src, &srcinc, DATETIME_YEAR);
231  }
232  break;
233 
234  case DATETIME_YEAR:
235  if (src->year < incr->year) { /* SIGN CHANGE */
236  src->year = incr->year - src->year;
238  tinc.year = 0;
239  src->month = 0;
240  datetime_increment(src, &tinc); /* no sign change */
241  }
242  else
243  src->year -= incr->year;
244  break;
245  }
246  }
247 
248  else if (src->mode == DATETIME_ABSOLUTE) {
249  DateTime srcinc, tinc, cpsrc;
250  int i, newdays, borrow = 0;
251 
252 
253  datetime_copy(&srcinc, incr); /* makes srcinc valid incr */
254  switch (field) {
255  case DATETIME_SECOND:
256  if (src->second < incr->second) {
257  borrow = 1 + (incr->second - src->second - 1) / 60;
258  src->second += borrow * 60;
259  }
260  src->second -= incr->second;
261  if (borrow) {
262  srcinc.minute = borrow;
263  _datetime_subtract_field(src, &srcinc, DATETIME_MINUTE);
264  }
265  break;
266 
267  case DATETIME_MINUTE:
268  if (src->minute < incr->minute) {
269  borrow = 1 + (incr->minute - src->minute - 1) / 60;
270  src->minute += borrow * 60;
271  }
272  src->minute -= incr->minute;
273  if (borrow) {
274  srcinc.hour = borrow;
275  _datetime_subtract_field(src, &srcinc, DATETIME_HOUR);
276  }
277  break;
278 
279  case DATETIME_HOUR:
280  if (src->hour < incr->hour) {
281  borrow = 1 + (incr->hour - src->hour - 1) / 24;
282  src->hour += borrow * 24;
283  }
284  src->hour -= incr->hour;
285  if (borrow) {
286  srcinc.day = borrow;
287  _datetime_subtract_field(src, &srcinc, DATETIME_DAY);
288  }
289  break;
290 
291  case DATETIME_DAY:
292 
293  if (src->day <= incr->day) {
294  datetime_copy(&cpsrc, src);
296  DATETIME_MONTH, -1);
297  datetime_set_increment_type(&cpsrc, &tinc);
298  tinc.month = 1;
299  newdays = src->day;
300  while (newdays <= incr->day) {
301  _datetime_subtract_field(&cpsrc, &tinc, DATETIME_MONTH);
302  newdays +=
303  datetime_days_in_month(cpsrc.year, cpsrc.month,
304  cpsrc.positive);
305  borrow++;
306  }
307  src->day = newdays;
308  }
309  src->day -= incr->day;
310  if (borrow) {
311  /*
312  src->year = cpsrc.year;
313  src->month = cpsrc.month;
314  src->positive = cpsrc.positive;
315  */
316  /* check here & below - srcinc may be a day-second interval - mess anything up? */
317  srcinc.month = borrow;
318  _datetime_subtract_field(src, &srcinc, DATETIME_MONTH);
319  }
320  break;
321 
322  case DATETIME_MONTH:
323  if (src->month <= incr->month) {
324  borrow = 1 + (incr->month - src->month) / 12;
325  src->month += borrow * 12;
326  }
327  src->month -= incr->month;
328  if (borrow) {
329  srcinc.year = borrow;
330  _datetime_subtract_field(src, &srcinc, DATETIME_YEAR);
331  }
332  break;
333 
334  case DATETIME_YEAR:
335  if (src->year <= incr->year) { /* SIGN CHANGE */
336  datetime_set_increment_type(src, &tinc);
337  tinc.positive = src->positive;
339  tinc.month = src->month - 1; /* convert to REL */
340  src->year = incr->year - src->year + 1;
341  /* +1 to skip 0 */
343  tinc.year = 0;
344  src->month = 1;
345  datetime_increment(src, &tinc); /* no sign change */
346  }
347  else { /* have to convert to days */
348  tinc.day = src->day - 1; /* convert to REL */
349  for (i = src->month - 1; i > 0; i--) {
350  tinc.day +=
352  src->positive);
353  }
354  tinc.hour = src->hour;
355  tinc.minute = src->minute;
356  tinc.second = src->second;
357  src->year = incr->year - src->year + 1;
358  /* +1 to skip 0 */
360  src->month = 1;
361  src->day = 1;
362  src->hour = src->minute = 0;
363  src->second = 0;
364  datetime_increment(src, &tinc); /* no sign change */
365  }
366  }
367  else
368  src->year -= incr->year;
369  break;
370  }
371  }
372 
373  return 0;
374 }
375 
376 /*****************************************************************/
377 
378 /* When absolute is zero, all fields carry toward the future */
379 /* When absolute is one, sign of datetime is ignored */
380 static int _datetime_carry(DateTime * dt, int absolute)
381 {
382  int i, carry;
383 
384  /* normalize day-sec (same for ABSOLUTE & RELATIVE) */
385  for (i = dt->to; i > dt->from && i > DATETIME_DAY; i--) {
386  switch (i) {
387  case DATETIME_SECOND:
388  if (dt->second >= 60.) {
389  carry = dt->second / 60.;
390  dt->minute += carry;
391  dt->second -= carry * 60;
392  }
393  break;
394  case DATETIME_MINUTE:
395  if (dt->minute >= 60) {
396  carry = dt->minute / 60;
397  dt->hour += carry;
398  dt->minute -= carry * 60;
399  }
400  break;
401  case DATETIME_HOUR:
402  if (dt->hour >= 24) {
403  carry = dt->hour / 24;
404  dt->day += carry;
405  dt->hour -= carry * 24;
406  }
407  break;
408  }
409  }
410 
411  /* give year a SIGN, temporarily */
412  if (!absolute && !dt->positive && dt->mode == DATETIME_ABSOLUTE) {
413  dt->year = -dt->year;
414  }
415 
416  if (dt->from == DATETIME_YEAR && dt->to >= DATETIME_MONTH) {
417 
418  /* normalize yr-mo */
419  if (dt->mode == DATETIME_ABSOLUTE) {
420  if (dt->month > 12) { /* month will never be zero */
421  carry = (dt->month - 1) / 12; /* no carry until 13 */
422  dt->year += carry;
423  if (dt->year == 0)
424  dt->year = 1;
425  dt->month -= carry * 12;
426  /*
427  if(dt->month == 0) dt->month = 1;
428  shouldn't happen */
429  }
430  }
431  else {
432  if (dt->month >= 12) {
433  carry = dt->month / 12;
434  dt->year += carry;
435  dt->month -= carry * 12;
436  }
437  }
438 
439  }
440 
441  /* normalize yr-day */
442  if (dt->mode == DATETIME_ABSOLUTE && dt->to > DATETIME_MONTH) {
443 
444  while (dt->day >
445  datetime_days_in_month(dt->year, dt->month, dt->positive)) {
446  dt->day -=
447  datetime_days_in_month(dt->year, dt->month, dt->positive);
448  if (dt->month == 12) { /* carry to year */
449  dt->year++;
450  if (dt->year == 0)
451  dt->year = 1;
452  dt->month = 1;
453  }
454  else /* no carry to year */
455  dt->month++;
456 
457  } /* end while */
458  } /* end if */
459 
460  /* undo giving year a SIGN, temporarily */
461  if (!absolute && dt->mode == DATETIME_ABSOLUTE) {
462  if (dt->year < 0) {
463  dt->year = -dt->year;
464  dt->positive = 0;
465  }
466  else
467  dt->positive = 1;
468  }
469 
470  return 0;
471 }
472 
473 static int _datetime_add_field(DateTime * src, DateTime * incr, int field)
474 {
475  switch (field) {
476  case DATETIME_SECOND:
477  src->second += incr->second;
478  break;
479  case DATETIME_MINUTE:
480  src->minute += incr->minute;
481  break;
482  case DATETIME_HOUR:
483  src->hour += incr->hour;
484  break;
485  case DATETIME_DAY:
486  src->day += incr->day;
487  break;
488  case DATETIME_MONTH:
489  src->month += incr->month;
490  break;
491  case DATETIME_YEAR:
492  src->year += incr->year;
493  break;
494  }
495  if (src->mode == DATETIME_RELATIVE)
496  _datetime_carry(src, 1); /* do carries using absolute values */
497  else
498  _datetime_carry(src, 0); /* do carries toward future */
499 
500  return 0;
501 }
int hour
Definition: datetime.h:23
int datetime_increment(DateTime *src, DateTime *incr)
This function changes the &#39;src&#39; date/time data based on the &#39;incr&#39; The type (mode/from/to) of the &#39;sr...
Definition: incr1.c:67
#define DATETIME_SECOND
Definition: datetime.h:15
int day
Definition: datetime.h:22
double second
Definition: datetime.h:24
#define DATETIME_MONTH
Definition: datetime.h:11
#define DATETIME_MINUTE
Definition: datetime.h:14
int datetime_is_valid_increment(const DateTime *src, const DateTime *incr)
Returns: datetime_check_increment(src, incr) == 0.
Definition: incr2.c:21
int from
Definition: datetime.h:20
int datetime_error_code(void)
returns an error code
int mode
Definition: datetime.h:19
int datetime_in_interval_day_second(int x)
#define DATETIME_RELATIVE
Definition: datetime.h:5
int year
Definition: datetime.h:22
#define DATETIME_YEAR
Definition: datetime.h:10
int positive
Definition: datetime.h:25
void datetime_copy(DateTime *src, const DateTime *dst)
Copies the DateTime [into/from ???] src.
Definition: datetime/copy.c:20
void datetime_invert_sign(DateTime *dt)
Definition: sign.c:80
int datetime_days_in_month(int year, int month, int ad)
returns number of days in &#39;month&#39; of a particular &#39;year&#39;
Definition: datetime/misc.c:64
#define DATETIME_DAY
Definition: datetime.h:12
int month
Definition: datetime.h:22
int datetime_set_increment_type(const DateTime *src, DateTime *incr)
src must be legal This is a convenience routine which is implemented as follows:
Definition: incr3.c:86
int to
Definition: datetime.h:20
int datetime_in_interval_year_month(int x)
#define DATETIME_ABSOLUTE
Definition: datetime.h:4
int datetime_change_from_to(DateTime *dt, int from, int to, int round)
Changes the from/to of the type for dt. The &#39;from/to&#39; must be legal values for the mode of dt; (if th...
Definition: change.c:55
#define DATETIME_HOUR
Definition: datetime.h:13
int minute
Definition: datetime.h:23