GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-8cbe8fef7c
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  */
67 
69 {
70  int i, relfrom;
71  DateTime cpdt, *dt;
72 
73  if (!datetime_is_valid_increment(src, incr))
74  return datetime_error_code();
75 
76  /* special case - incrementing a relative might try to increment
77  or borrow from a "lower" field than src has,
78  so we use a copy to change from */
79 
80  if (src->mode == DATETIME_RELATIVE) {
81  datetime_copy(&cpdt, src);
83  : DATETIME_YEAR;
84  datetime_change_from_to(&cpdt, relfrom, src->to, -1); /* min. from */
85  dt = &cpdt;
86  }
87  else
88  dt = src;
89 
90  /* need to call carry first? (just to make sure?) */
91  /*
92  fprintf (stdout,"DEBUG: INCR %.12lf %.12lf = %.12lf\n",
93  _debug_decimal(dt), _debug_decimal(incr),
94  _debug_decimal(dt)+_debug_decimal(incr));
95  */
96 
97  /* no sign change, just add */
98  if ((dt->positive && incr->positive) ||
99  (dt->mode == DATETIME_RELATIVE && !dt->positive && !incr->positive)) {
100 
101  for (i = incr->to; i >= incr->from; i--) {
102  _datetime_add_field(dt, incr, i);
103  }
104  }
105 
106  else if (!incr->positive || dt->mode == DATETIME_RELATIVE) {
107 
108  for (i = incr->to; i >= incr->from; i--) {
109  _datetime_subtract_field(dt, incr, i);
110  }
111  }
112 
113  /* now only two special cases of bc ABSOLUTE left */
114 
115  else if (!incr->positive) { /* incr is negative, dt is positive */
116 
117  for (i = incr->to; i > DATETIME_YEAR; i--) {
118  _datetime_subtract_field(dt, incr, i);
119  }
120  _datetime_add_field(dt, incr, DATETIME_YEAR);
121  }
122  else { /* incr is positive, dt is negative */
123 
124  for (i = incr->to; i > DATETIME_YEAR; i--) {
125  _datetime_add_field(dt, incr, i);
126  }
127  _datetime_subtract_field(dt, incr, DATETIME_YEAR);
128  }
129  /*
130  fprintf (stdout,"DEBUG: INCR RESULT = %.12lf\n", _debug_decimal(dt));
131  */
132  if (src->mode == DATETIME_RELATIVE) {
133  datetime_change_from_to(dt, src->from, src->to, -1);
134 
135  /* copy dt back into src to return */
136  datetime_copy(src, dt);
137  }
138 
139  return 0;
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, int field)
156 {
157 
158  if (src->mode == DATETIME_RELATIVE) {
159  DateTime srcinc, tinc;
160  int borrow = 0;
161 
162  datetime_copy(&tinc, src);
163  datetime_copy(&srcinc, incr);
164  switch (field) {
165  case DATETIME_SECOND:
166  /* no "-1" here - remember seconds is floating point */
167  /* might result in over borrowing, so have to check */
168  if (src->second < incr->second) {
169  if ((int)(incr->second - src->second) ==
170  (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  datetime_copy(&srcinc, incr); /* makes srcinc valid incr */
253  switch (field) {
254  case DATETIME_SECOND:
255  if (src->second < incr->second) {
256  borrow = 1 + (incr->second - src->second - 1) / 60;
257  src->second += borrow * 60;
258  }
259  src->second -= incr->second;
260  if (borrow) {
261  srcinc.minute = borrow;
262  _datetime_subtract_field(src, &srcinc, DATETIME_MINUTE);
263  }
264  break;
265 
266  case DATETIME_MINUTE:
267  if (src->minute < incr->minute) {
268  borrow = 1 + (incr->minute - src->minute - 1) / 60;
269  src->minute += borrow * 60;
270  }
271  src->minute -= incr->minute;
272  if (borrow) {
273  srcinc.hour = borrow;
274  _datetime_subtract_field(src, &srcinc, DATETIME_HOUR);
275  }
276  break;
277 
278  case DATETIME_HOUR:
279  if (src->hour < incr->hour) {
280  borrow = 1 + (incr->hour - src->hour - 1) / 24;
281  src->hour += borrow * 24;
282  }
283  src->hour -= incr->hour;
284  if (borrow) {
285  srcinc.day = borrow;
286  _datetime_subtract_field(src, &srcinc, DATETIME_DAY);
287  }
288  break;
289 
290  case DATETIME_DAY:
291 
292  if (src->day <= incr->day) {
293  datetime_copy(&cpsrc, src);
295  -1);
296  datetime_set_increment_type(&cpsrc, &tinc);
297  tinc.month = 1;
298  newdays = src->day;
299  while (newdays <= incr->day) {
300  _datetime_subtract_field(&cpsrc, &tinc, DATETIME_MONTH);
301  newdays += datetime_days_in_month(cpsrc.year, cpsrc.month,
302  cpsrc.positive);
303  borrow++;
304  }
305  src->day = newdays;
306  }
307  src->day -= incr->day;
308  if (borrow) {
309  /*
310  src->year = cpsrc.year;
311  src->month = cpsrc.month;
312  src->positive = cpsrc.positive;
313  */
314  /* check here & below - srcinc may be a day-second interval -
315  * mess anything up? */
316  srcinc.month = borrow;
317  _datetime_subtract_field(src, &srcinc, DATETIME_MONTH);
318  }
319  break;
320 
321  case DATETIME_MONTH:
322  if (src->month <= incr->month) {
323  borrow = 1 + (incr->month - src->month) / 12;
324  src->month += borrow * 12;
325  }
326  src->month -= incr->month;
327  if (borrow) {
328  srcinc.year = borrow;
329  _datetime_subtract_field(src, &srcinc, DATETIME_YEAR);
330  }
331  break;
332 
333  case DATETIME_YEAR:
334  if (src->year <= incr->year) { /* SIGN CHANGE */
335  datetime_set_increment_type(src, &tinc);
336  tinc.positive = src->positive;
338  tinc.month = src->month - 1; /* convert to REL */
339  src->year = incr->year - src->year + 1;
340  /* +1 to skip 0 */
342  tinc.year = 0;
343  src->month = 1;
344  datetime_increment(src, &tinc); /* no sign change */
345  }
346  else { /* have to convert to days */
347  tinc.day = src->day - 1; /* convert to REL */
348  for (i = src->month - 1; i > 0; i--) {
349  tinc.day +=
350  datetime_days_in_month(src->year, i, src->positive);
351  }
352  tinc.hour = src->hour;
353  tinc.minute = src->minute;
354  tinc.second = src->second;
355  src->year = incr->year - src->year + 1;
356  /* +1 to skip 0 */
358  src->month = 1;
359  src->day = 1;
360  src->hour = src->minute = 0;
361  src->second = 0;
362  datetime_increment(src, &tinc); /* no sign change */
363  }
364  }
365  else
366  src->year -= incr->year;
367  break;
368  }
369  }
370 
371  return 0;
372 }
373 
374 /*****************************************************************/
375 
376 /* When absolute is zero, all fields carry toward the future */
377 /* When absolute is one, sign of datetime is ignored */
378 static int _datetime_carry(DateTime *dt, int absolute)
379 {
380  int i, carry;
381 
382  /* normalize day-sec (same for ABSOLUTE & RELATIVE) */
383  for (i = dt->to; i > dt->from && i > DATETIME_DAY; i--) {
384  switch (i) {
385  case DATETIME_SECOND:
386  if (dt->second >= 60.) {
387  carry = dt->second / 60.;
388  dt->minute += carry;
389  dt->second -= carry * 60;
390  }
391  break;
392  case DATETIME_MINUTE:
393  if (dt->minute >= 60) {
394  carry = dt->minute / 60;
395  dt->hour += carry;
396  dt->minute -= carry * 60;
397  }
398  break;
399  case DATETIME_HOUR:
400  if (dt->hour >= 24) {
401  carry = dt->hour / 24;
402  dt->day += carry;
403  dt->hour -= carry * 24;
404  }
405  break;
406  }
407  }
408 
409  /* give year a SIGN, temporarily */
410  if (!absolute && !dt->positive && dt->mode == DATETIME_ABSOLUTE) {
411  dt->year = -dt->year;
412  }
413 
414  if (dt->from == DATETIME_YEAR && dt->to >= DATETIME_MONTH) {
415 
416  /* normalize yr-mo */
417  if (dt->mode == DATETIME_ABSOLUTE) {
418  if (dt->month > 12) { /* month will never be zero */
419  carry = (dt->month - 1) / 12; /* no carry until 13 */
420  dt->year += carry;
421  if (dt->year == 0)
422  dt->year = 1;
423  dt->month -= carry * 12;
424  /*
425  if(dt->month == 0) dt->month = 1;
426  shouldn't happen */
427  }
428  }
429  else {
430  if (dt->month >= 12) {
431  carry = dt->month / 12;
432  dt->year += carry;
433  dt->month -= carry * 12;
434  }
435  }
436  }
437 
438  /* normalize yr-day */
439  if (dt->mode == DATETIME_ABSOLUTE && dt->to > DATETIME_MONTH) {
440 
441  while (dt->day >
442  datetime_days_in_month(dt->year, dt->month, dt->positive)) {
443  dt->day -=
444  datetime_days_in_month(dt->year, dt->month, dt->positive);
445  if (dt->month == 12) { /* carry to year */
446  dt->year++;
447  if (dt->year == 0)
448  dt->year = 1;
449  dt->month = 1;
450  }
451  else /* no carry to year */
452  dt->month++;
453 
454  } /* end while */
455  } /* end if */
456 
457  /* undo giving year a SIGN, temporarily */
458  if (!absolute && dt->mode == DATETIME_ABSOLUTE) {
459  if (dt->year < 0) {
460  dt->year = -dt->year;
461  dt->positive = 0;
462  }
463  else
464  dt->positive = 1;
465  }
466 
467  return 0;
468 }
469 
470 static int _datetime_add_field(DateTime *src, DateTime *incr, int field)
471 {
472  switch (field) {
473  case DATETIME_SECOND:
474  src->second += incr->second;
475  break;
476  case DATETIME_MINUTE:
477  src->minute += incr->minute;
478  break;
479  case DATETIME_HOUR:
480  src->hour += incr->hour;
481  break;
482  case DATETIME_DAY:
483  src->day += incr->day;
484  break;
485  case DATETIME_MONTH:
486  src->month += incr->month;
487  break;
488  case DATETIME_YEAR:
489  src->year += incr->year;
490  break;
491  }
492  if (src->mode == DATETIME_RELATIVE)
493  _datetime_carry(src, 1); /* do carries using absolute values */
494  else
495  _datetime_carry(src, 0); /* do carries toward future */
496 
497  return 0;
498 }
#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:61
int datetime_error_code(void)
returns an error code
void datetime_invert_sign(DateTime *dt)
Definition: sign.c:76
int datetime_is_valid_increment(const DateTime *src, const DateTime *incr)
Returns: datetime_check_increment(src, incr) == 0.
Definition: incr2.c:20
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
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:84
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:20
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 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