GRASS GIS 8 Programmer's Manual 8.3.2(2024)-exported
Loading...
Searching...
No Matches
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
9static int _datetime_add_field(DateTime *, DateTime *, int);
10static int _datetime_subtract_field(DateTime *, DateTime *, int);
11
12/*****************************************************************/
13#if 0 /* unused */
14static double _debug_decimal(DateTime * dt)
15{
16 double dtdec = 0.0;
17
18 if (dt->mode == DATETIME_RELATIVE) {
19 if (datetime_in_interval_year_month(dt->from)) {
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
68int datetime_increment(DateTime *src, DateTime *incr)
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);
82 relfrom = datetime_in_interval_day_second(src->from) ? DATETIME_DAY
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
155static 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);
294 datetime_change_from_to(&cpsrc, DATETIME_YEAR, DATETIME_MONTH,
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;
337 if (datetime_in_interval_year_month(tinc.to)) {
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 */
378static 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
470static 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}
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
void datetime_copy(DateTime *dst, const DateTime *src)
Copies the DateTime [into/from ???] src.
Definition copy.c:20
int datetime_error_code(void)
returns an error code
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_is_valid_increment(const DateTime *src, const DateTime *incr)
Returns: datetime_check_increment(src, incr) == 0.
Definition incr2.c:20
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_days_in_month(int year, int month, int ad)
returns number of days in 'month' of a particular 'year'
Definition misc.c:61
void datetime_invert_sign(DateTime *dt)
Definition sign.c:76
int datetime_in_interval_day_second(int x)
Definition type.c:152
int datetime_in_interval_year_month(int x)
Definition type.c:147