GRASS 8 Programmer's Manual 8.6.0dev(2026)-56a9afeb9f
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) {
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);
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 */
153static int _datetime_subtract_field(DateTime *src, DateTime *incr, int field)
154{
155
156 if (src->mode == DATETIME_RELATIVE) {
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) {
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);
295 tinc.month = 1;
296 newdays = src->day;
297 while (newdays <= incr->day) {
298 _datetime_subtract_field(&cpsrc, &tinc, DATETIME_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 */
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 */
376static 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 -=
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
468static 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'
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.
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