GRASS 8 Programmer's Manual  8.5.0dev(2025)-c070206eb1
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
43  <b>datetime_is_valid_increment()</b>,
44  * <b>datetime_check_increment()</b>
45  * Returns:
46  * 0: OK
47  * -1: 'incr' is invalid increment for 'src'
48  * For src.mode ABSOLUTE,
49  * <ul>
50  <li> positive 'incr' moves into the future,
51  </li>
52  <li> negative 'incr' moves into the past.
53  </li>
54  <li> BC implies the year is negative, but all else is positive. Also, year==0
55  * is illegal: adding 1 year to 1[bc] gives 1[ad]
56  </li></ul>
57  * The 'fracsec' in 'src' is preserved.
58  * The 'from/to' of the 'src' is preserved.
59  * A timezone in 'src' is allowed - it's presence is ignored.
60  * NOTE: There is no datetime_decrement() To decrement, set the 'incr' negative.
61 
62  *
63  * \param src
64  * \param incr
65  * \return int
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);
82  : DATETIME_YEAR;
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  When calling, the field must be
144  in the range of src, but this is not enforced here.
145 
146  The only thing used from the "incr" DateTime is the value of
147  the field being subtracted and the "from" & "to"
148 
149  by the time we get here, if src is RELATIVE, src->from should
150  already be minimized to allow borrowing from "lower" fields
151 
152  */
153 static int _datetime_subtract_field(DateTime *src, DateTime *incr, int field)
154 {
155 
156  if (src->mode == DATETIME_RELATIVE) {
157  DateTime srcinc, tinc;
158  int borrow = 0;
159 
160  datetime_copy(&tinc, src);
161  datetime_copy(&srcinc, incr);
162  switch (field) {
163  case DATETIME_SECOND:
164  /* no "-1" here - remember seconds is floating point */
165  /* might result in over borrowing, so have to check */
166  if (src->second < incr->second) {
167  if ((int)(incr->second - src->second) ==
168  (incr->second - src->second)) { /* diff is integer */
169  borrow = 1 + (incr->second - src->second - 1) / 60;
170  }
171  else
172  borrow = 1 + (incr->second - src->second) / 60;
173  src->second += borrow * 60;
174  }
175  src->second -= incr->second;
176  if (borrow) {
177  srcinc.minute = borrow;
178  _datetime_subtract_field(src, &srcinc, DATETIME_MINUTE);
179  }
180  break;
181 
182  case DATETIME_MINUTE:
183  if (src->minute < incr->minute) {
184  borrow = 1 + (incr->minute - src->minute - 1) / 60;
185  src->minute += borrow * 60;
186  }
187  src->minute -= incr->minute;
188  if (borrow) {
189  srcinc.hour = borrow;
190  _datetime_subtract_field(src, &srcinc, DATETIME_HOUR);
191  }
192  break;
193 
194  case DATETIME_HOUR:
195  if (src->hour < incr->hour) {
196  borrow = 1 + (incr->hour - src->hour - 1) / 24;
197  src->hour += borrow * 24;
198  }
199  src->hour -= incr->hour;
200  if (borrow) {
201  srcinc.day = borrow;
202  _datetime_subtract_field(src, &srcinc, DATETIME_DAY);
203  }
204  break;
205 
206  case DATETIME_DAY:
207  if (src->day < incr->day) { /* SIGN CHANGE */
208  src->day = incr->day - src->day;
210  tinc.day = 0;
211  src->hour = 0;
212  src->minute = 0;
213  src->second = 0.0;
214  datetime_increment(src, &tinc); /* no sign change */
215  }
216  else
217  src->day -= incr->day;
218  break;
219 
220  case DATETIME_MONTH:
221  if (src->month < incr->month) {
222  borrow = 1 + (incr->month - src->month - 1) / 12;
223  src->month += borrow * 12;
224  }
225  src->month -= incr->month;
226  if (borrow) {
227  srcinc.year = borrow;
228  _datetime_subtract_field(src, &srcinc, DATETIME_YEAR);
229  }
230  break;
231 
232  case DATETIME_YEAR:
233  if (src->year < incr->year) { /* SIGN CHANGE */
234  src->year = incr->year - src->year;
236  tinc.year = 0;
237  src->month = 0;
238  datetime_increment(src, &tinc); /* no sign change */
239  }
240  else
241  src->year -= incr->year;
242  break;
243  }
244  }
245 
246  else if (src->mode == DATETIME_ABSOLUTE) {
247  DateTime srcinc, tinc, cpsrc;
248  int i, newdays, borrow = 0;
249 
250  datetime_copy(&srcinc, incr); /* makes srcinc valid incr */
251  switch (field) {
252  case DATETIME_SECOND:
253  if (src->second < incr->second) {
254  borrow = 1 + (incr->second - src->second - 1) / 60;
255  src->second += borrow * 60;
256  }
257  src->second -= incr->second;
258  if (borrow) {
259  srcinc.minute = borrow;
260  _datetime_subtract_field(src, &srcinc, DATETIME_MINUTE);
261  }
262  break;
263 
264  case DATETIME_MINUTE:
265  if (src->minute < incr->minute) {
266  borrow = 1 + (incr->minute - src->minute - 1) / 60;
267  src->minute += borrow * 60;
268  }
269  src->minute -= incr->minute;
270  if (borrow) {
271  srcinc.hour = borrow;
272  _datetime_subtract_field(src, &srcinc, DATETIME_HOUR);
273  }
274  break;
275 
276  case DATETIME_HOUR:
277  if (src->hour < incr->hour) {
278  borrow = 1 + (incr->hour - src->hour - 1) / 24;
279  src->hour += borrow * 24;
280  }
281  src->hour -= incr->hour;
282  if (borrow) {
283  srcinc.day = borrow;
284  _datetime_subtract_field(src, &srcinc, DATETIME_DAY);
285  }
286  break;
287 
288  case DATETIME_DAY:
289 
290  if (src->day <= incr->day) {
291  datetime_copy(&cpsrc, src);
293  -1);
294  datetime_set_increment_type(&cpsrc, &tinc);
295  tinc.month = 1;
296  newdays = src->day;
297  while (newdays <= incr->day) {
298  _datetime_subtract_field(&cpsrc, &tinc, DATETIME_MONTH);
299  newdays += datetime_days_in_month(cpsrc.year, cpsrc.month,
300  cpsrc.positive);
301  borrow++;
302  }
303  src->day = newdays;
304  }
305  src->day -= incr->day;
306  if (borrow) {
307  /*
308  src->year = cpsrc.year;
309  src->month = cpsrc.month;
310  src->positive = cpsrc.positive;
311  */
312  /* check here & below - srcinc may be a day-second interval -
313  * mess anything up? */
314  srcinc.month = borrow;
315  _datetime_subtract_field(src, &srcinc, DATETIME_MONTH);
316  }
317  break;
318 
319  case DATETIME_MONTH:
320  if (src->month <= incr->month) {
321  borrow = 1 + (incr->month - src->month) / 12;
322  src->month += borrow * 12;
323  }
324  src->month -= incr->month;
325  if (borrow) {
326  srcinc.year = borrow;
327  _datetime_subtract_field(src, &srcinc, DATETIME_YEAR);
328  }
329  break;
330 
331  case DATETIME_YEAR:
332  if (src->year <= incr->year) { /* SIGN CHANGE */
333  datetime_set_increment_type(src, &tinc);
334  tinc.positive = src->positive;
336  tinc.month = src->month - 1; /* convert to REL */
337  src->year = incr->year - src->year + 1;
338  /* +1 to skip 0 */
340  tinc.year = 0;
341  src->month = 1;
342  datetime_increment(src, &tinc); /* no sign change */
343  }
344  else { /* have to convert to days */
345  tinc.day = src->day - 1; /* convert to REL */
346  for (i = src->month - 1; i > 0; i--) {
347  tinc.day +=
348  datetime_days_in_month(src->year, i, src->positive);
349  }
350  tinc.hour = src->hour;
351  tinc.minute = src->minute;
352  tinc.second = src->second;
353  src->year = incr->year - src->year + 1;
354  /* +1 to skip 0 */
356  src->month = 1;
357  src->day = 1;
358  src->hour = src->minute = 0;
359  src->second = 0;
360  datetime_increment(src, &tinc); /* no sign change */
361  }
362  }
363  else
364  src->year -= incr->year;
365  break;
366  }
367  }
368 
369  return 0;
370 }
371 
372 /*****************************************************************/
373 
374 /* When absolute is zero, all fields carry toward the future */
375 /* When absolute is one, sign of datetime is ignored */
376 static int _datetime_carry(DateTime *dt, int absolute)
377 {
378  int i, carry;
379 
380  /* normalize day-sec (same for ABSOLUTE & RELATIVE) */
381  for (i = dt->to; i > dt->from && i > DATETIME_DAY; i--) {
382  switch (i) {
383  case DATETIME_SECOND:
384  if (dt->second >= 60.) {
385  carry = dt->second / 60.;
386  dt->minute += carry;
387  dt->second -= carry * 60;
388  }
389  break;
390  case DATETIME_MINUTE:
391  if (dt->minute >= 60) {
392  carry = dt->minute / 60;
393  dt->hour += carry;
394  dt->minute -= carry * 60;
395  }
396  break;
397  case DATETIME_HOUR:
398  if (dt->hour >= 24) {
399  carry = dt->hour / 24;
400  dt->day += carry;
401  dt->hour -= carry * 24;
402  }
403  break;
404  }
405  }
406 
407  /* give year a SIGN, temporarily */
408  if (!absolute && !dt->positive && dt->mode == DATETIME_ABSOLUTE) {
409  dt->year = -dt->year;
410  }
411 
412  if (dt->from == DATETIME_YEAR && dt->to >= DATETIME_MONTH) {
413 
414  /* normalize yr-mo */
415  if (dt->mode == DATETIME_ABSOLUTE) {
416  if (dt->month > 12) { /* month will never be zero */
417  carry = (dt->month - 1) / 12; /* no carry until 13 */
418  dt->year += carry;
419  if (dt->year == 0)
420  dt->year = 1;
421  dt->month -= carry * 12;
422  /*
423  if(dt->month == 0) dt->month = 1;
424  shouldn't happen */
425  }
426  }
427  else {
428  if (dt->month >= 12) {
429  carry = dt->month / 12;
430  dt->year += carry;
431  dt->month -= carry * 12;
432  }
433  }
434  }
435 
436  /* normalize yr-day */
437  if (dt->mode == DATETIME_ABSOLUTE && dt->to > DATETIME_MONTH) {
438 
439  while (dt->day >
440  datetime_days_in_month(dt->year, dt->month, dt->positive)) {
441  dt->day -=
442  datetime_days_in_month(dt->year, dt->month, dt->positive);
443  if (dt->month == 12) { /* carry to year */
444  dt->year++;
445  if (dt->year == 0)
446  dt->year = 1;
447  dt->month = 1;
448  }
449  else /* no carry to year */
450  dt->month++;
451 
452  } /* end while */
453  } /* end if */
454 
455  /* undo giving year a SIGN, temporarily */
456  if (!absolute && dt->mode == DATETIME_ABSOLUTE) {
457  if (dt->year < 0) {
458  dt->year = -dt->year;
459  dt->positive = 0;
460  }
461  else
462  dt->positive = 1;
463  }
464 
465  return 0;
466 }
467 
468 static int _datetime_add_field(DateTime *src, DateTime *incr, int field)
469 {
470  switch (field) {
471  case DATETIME_SECOND:
472  src->second += incr->second;
473  break;
474  case DATETIME_MINUTE:
475  src->minute += incr->minute;
476  break;
477  case DATETIME_HOUR:
478  src->hour += incr->hour;
479  break;
480  case DATETIME_DAY:
481  src->day += incr->day;
482  break;
483  case DATETIME_MONTH:
484  src->month += incr->month;
485  break;
486  case DATETIME_YEAR:
487  src->year += incr->year;
488  break;
489  }
490  if (src->mode == DATETIME_RELATIVE)
491  _datetime_carry(src, 1); /* do carries using absolute values */
492  else
493  _datetime_carry(src, 0); /* do carries toward future */
494 
495  return 0;
496 }
#define DATETIME_ABSOLUTE
Definition: datetime.h:4
#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_in_interval_day_second(int x)
int datetime_days_in_month(int year, int month, int ad)
returns number of days in 'month' of a particular 'year'
Definition: datetime/misc.c:58
int datetime_error_code(void)
returns an error code
void datetime_invert_sign(DateTime *dt)
Definition: sign.c:71
int datetime_is_valid_increment(const DateTime *src, const DateTime *incr)
Returns: datetime_check_increment(src, incr) == 0.
Definition: incr2.c:19
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
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:82
int datetime_in_interval_year_month(int x)
void datetime_copy(DateTime *src, const DateTime *dst)
Copies the DateTime [into/from ???] src.
Definition: datetime/copy.c:19
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 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 from
Definition: datetime.h:19
int hour
Definition: datetime.h:22
int minute
Definition: datetime.h:22
int day
Definition: datetime.h:21