GRASS Programmer's Manual  6.4.2(2012)
incr1.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 1995.  Bill Brown <brown@gis.uiuc.edu> & Michael Shapiro
00003  *
00004  * This program is free software under the GPL (>=v2)
00005  * Read the file GPL.TXT coming with GRASS for details.
00006  */
00007 #include <grass/datetime.h>
00008 
00009 static int _datetime_add_field(DateTime *, DateTime *, int);
00010 static int _datetime_subtract_field(DateTime *, DateTime *, int);
00011 
00012 /*****************************************************************/
00013 #if 0                           /* unused */
00014 static double _debug_decimal(DateTime * dt)
00015 {
00016     double dtdec = 0.0;
00017 
00018     if (dt->mode == DATETIME_RELATIVE) {
00019         if (datetime_in_interval_year_month(dt->from)) {
00020             dtdec = dt->year + dt->month / 12.;
00021         }
00022         else {
00023             dtdec = dt->day / 365.25 +
00024                 dt->hour / 8766. + dt->minute / 525960.
00025                 + dt->second / 31557600.;
00026         }
00027     }
00028     if (dt->positive)
00029         return (dtdec);
00030     return (-dtdec);
00031 }
00032 #endif /* unused */
00033 
00034 /*****************************************************************/
00035 
00067 int datetime_increment(DateTime * src, DateTime * incr)
00068 {
00069     int i, relfrom;
00070     DateTime cpdt, *dt;
00071 
00072     if (!datetime_is_valid_increment(src, incr))
00073         return datetime_error_code();
00074 
00075     /* special case - incrementing a relative might try to increment 
00076        or borrow from a "lower" field than src has, 
00077        so we use a copy to change from */
00078 
00079     if (src->mode == DATETIME_RELATIVE) {
00080         datetime_copy(&cpdt, src);
00081         relfrom = datetime_in_interval_day_second(src->from)
00082             ? DATETIME_DAY : DATETIME_YEAR;
00083         datetime_change_from_to(&cpdt, relfrom, src->to, -1);   /* min. from */
00084         dt = &cpdt;
00085     }
00086     else
00087         dt = src;
00088 
00089     /* need to call carry first? (just to make sure?) */
00090     /*
00091        fprintf (stdout,"DEBUG: INCR %.12lf %.12lf = %.12lf\n", 
00092        _debug_decimal(dt), _debug_decimal(incr), 
00093        _debug_decimal(dt)+_debug_decimal(incr)); 
00094      */
00095 
00096     /* no sign change, just add */
00097     if ((dt->positive && incr->positive) ||
00098         (dt->mode == DATETIME_RELATIVE && !dt->positive && !incr->positive)) {
00099 
00100         for (i = incr->to; i >= incr->from; i--) {
00101             _datetime_add_field(dt, incr, i);
00102         }
00103     }
00104 
00105     else if (!incr->positive || dt->mode == DATETIME_RELATIVE) {
00106 
00107         for (i = incr->to; i >= incr->from; i--) {
00108             _datetime_subtract_field(dt, incr, i);
00109         }
00110     }
00111 
00112     /* now only two special cases of bc ABSOLUTE left */
00113 
00114     else if (!incr->positive) { /* incr is negative, dt is positive */
00115 
00116         for (i = incr->to; i > DATETIME_YEAR; i--) {
00117             _datetime_subtract_field(dt, incr, i);
00118         }
00119         _datetime_add_field(dt, incr, DATETIME_YEAR);
00120     }
00121     else {                      /* incr is positive, dt is negative */
00122 
00123         for (i = incr->to; i > DATETIME_YEAR; i--) {
00124             _datetime_add_field(dt, incr, i);
00125         }
00126         _datetime_subtract_field(dt, incr, DATETIME_YEAR);
00127     }
00128     /*
00129        fprintf (stdout,"DEBUG: INCR RESULT = %.12lf\n", _debug_decimal(dt)); 
00130      */
00131     if (src->mode == DATETIME_RELATIVE) {
00132         datetime_change_from_to(dt, src->from, src->to, -1);
00133 
00134         /* copy dt back into src to return */
00135         datetime_copy(src, dt);
00136     }
00137 
00138     return 0;
00139 }
00140 
00141 
00142 /*****************************************************************/
00143 /*
00144    When calling, the field must be 
00145    in the range of src, but this is not enforced here.
00146 
00147    The only thing used from the "incr" DateTime is the value of
00148    the field being subtracted and the "from" & "to" 
00149 
00150    by the time we get here, if src is RELATIVE, src->from should
00151    already be minimized to allow borrowing from "lower" fields
00152 
00153  */
00154 
00155 static int _datetime_subtract_field(DateTime * src, DateTime * incr,
00156                                     int field)
00157 {
00158 
00159     if (src->mode == DATETIME_RELATIVE) {
00160         DateTime srcinc, tinc;
00161         int borrow = 0;
00162 
00163         datetime_copy(&tinc, src);
00164         datetime_copy(&srcinc, incr);
00165         switch (field) {
00166         case DATETIME_SECOND:
00167             /* no "-1" here - remember seconds is floating point */
00168             /* might result in over borrowing, so have to check */
00169             if (src->second < incr->second) {
00170                 if ((int)(incr->second - src->second) == (incr->second - src->second)) {        /* diff is integer */
00171                     borrow = 1 + (incr->second - src->second - 1) / 60;
00172                 }
00173                 else
00174                     borrow = 1 + (incr->second - src->second) / 60;
00175                 src->second += borrow * 60;
00176             }
00177             src->second -= incr->second;
00178             if (borrow) {
00179                 srcinc.minute = borrow;
00180                 _datetime_subtract_field(src, &srcinc, DATETIME_MINUTE);
00181             }
00182             break;
00183 
00184         case DATETIME_MINUTE:
00185             if (src->minute < incr->minute) {
00186                 borrow = 1 + (incr->minute - src->minute - 1) / 60;
00187                 src->minute += borrow * 60;
00188             }
00189             src->minute -= incr->minute;
00190             if (borrow) {
00191                 srcinc.hour = borrow;
00192                 _datetime_subtract_field(src, &srcinc, DATETIME_HOUR);
00193             }
00194             break;
00195 
00196         case DATETIME_HOUR:
00197             if (src->hour < incr->hour) {
00198                 borrow = 1 + (incr->hour - src->hour - 1) / 24;
00199                 src->hour += borrow * 24;
00200             }
00201             src->hour -= incr->hour;
00202             if (borrow) {
00203                 srcinc.day = borrow;
00204                 _datetime_subtract_field(src, &srcinc, DATETIME_DAY);
00205             }
00206             break;
00207 
00208         case DATETIME_DAY:
00209             if (src->day < incr->day) { /* SIGN CHANGE */
00210                 src->day = incr->day - src->day;
00211                 datetime_invert_sign(src);
00212                 tinc.day = 0;
00213                 src->hour = 0;
00214                 src->minute = 0;
00215                 src->second = 0.0;
00216                 datetime_increment(src, &tinc); /* no sign change */
00217             }
00218             else
00219                 src->day -= incr->day;
00220             break;
00221 
00222         case DATETIME_MONTH:
00223             if (src->month < incr->month) {
00224                 borrow = 1 + (incr->month - src->month - 1) / 12;
00225                 src->month += borrow * 12;
00226             }
00227             src->month -= incr->month;
00228             if (borrow) {
00229                 srcinc.year = borrow;
00230                 _datetime_subtract_field(src, &srcinc, DATETIME_YEAR);
00231             }
00232             break;
00233 
00234         case DATETIME_YEAR:
00235             if (src->year < incr->year) {       /* SIGN CHANGE */
00236                 src->year = incr->year - src->year;
00237                 datetime_invert_sign(src);
00238                 tinc.year = 0;
00239                 src->month = 0;
00240                 datetime_increment(src, &tinc); /* no sign change */
00241             }
00242             else
00243                 src->year -= incr->year;
00244             break;
00245         }
00246     }
00247 
00248     else if (src->mode == DATETIME_ABSOLUTE) {
00249         DateTime srcinc, tinc, cpsrc;
00250         int i, newdays, borrow = 0;
00251 
00252 
00253         datetime_copy(&srcinc, incr);   /* makes srcinc valid incr */
00254         switch (field) {
00255         case DATETIME_SECOND:
00256             if (src->second < incr->second) {
00257                 borrow = 1 + (incr->second - src->second - 1) / 60;
00258                 src->second += borrow * 60;
00259             }
00260             src->second -= incr->second;
00261             if (borrow) {
00262                 srcinc.minute = borrow;
00263                 _datetime_subtract_field(src, &srcinc, DATETIME_MINUTE);
00264             }
00265             break;
00266 
00267         case DATETIME_MINUTE:
00268             if (src->minute < incr->minute) {
00269                 borrow = 1 + (incr->minute - src->minute - 1) / 60;
00270                 src->minute += borrow * 60;
00271             }
00272             src->minute -= incr->minute;
00273             if (borrow) {
00274                 srcinc.hour = borrow;
00275                 _datetime_subtract_field(src, &srcinc, DATETIME_HOUR);
00276             }
00277             break;
00278 
00279         case DATETIME_HOUR:
00280             if (src->hour < incr->hour) {
00281                 borrow = 1 + (incr->hour - src->hour - 1) / 24;
00282                 src->hour += borrow * 24;
00283             }
00284             src->hour -= incr->hour;
00285             if (borrow) {
00286                 srcinc.day = borrow;
00287                 _datetime_subtract_field(src, &srcinc, DATETIME_DAY);
00288             }
00289             break;
00290 
00291         case DATETIME_DAY:
00292 
00293             if (src->day <= incr->day) {
00294                 datetime_copy(&cpsrc, src);
00295                 datetime_change_from_to(&cpsrc, DATETIME_YEAR,
00296                                         DATETIME_MONTH, -1);
00297                 datetime_set_increment_type(&cpsrc, &tinc);
00298                 tinc.month = 1;
00299                 newdays = src->day;
00300                 while (newdays <= incr->day) {
00301                     _datetime_subtract_field(&cpsrc, &tinc, DATETIME_MONTH);
00302                     newdays +=
00303                         datetime_days_in_month(cpsrc.year, cpsrc.month,
00304                                                cpsrc.positive);
00305                     borrow++;
00306                 }
00307                 src->day = newdays;
00308             }
00309             src->day -= incr->day;
00310             if (borrow) {
00311                 /*
00312                    src->year = cpsrc.year;
00313                    src->month = cpsrc.month;
00314                    src->positive = cpsrc.positive;
00315                  */
00316                 /* check here & below - srcinc may be a day-second interval - mess anything up? */
00317                 srcinc.month = borrow;
00318                 _datetime_subtract_field(src, &srcinc, DATETIME_MONTH);
00319             }
00320             break;
00321 
00322         case DATETIME_MONTH:
00323             if (src->month <= incr->month) {
00324                 borrow = 1 + (incr->month - src->month) / 12;
00325                 src->month += borrow * 12;
00326             }
00327             src->month -= incr->month;
00328             if (borrow) {
00329                 srcinc.year = borrow;
00330                 _datetime_subtract_field(src, &srcinc, DATETIME_YEAR);
00331             }
00332             break;
00333 
00334         case DATETIME_YEAR:
00335             if (src->year <= incr->year) {      /* SIGN CHANGE */
00336                 datetime_set_increment_type(src, &tinc);
00337                 tinc.positive = src->positive;
00338                 if (datetime_in_interval_year_month(tinc.to)) {
00339                     tinc.month = src->month - 1;        /* convert to REL */
00340                     src->year = incr->year - src->year + 1;
00341                     /* +1 to skip 0 */
00342                     datetime_invert_sign(src);
00343                     tinc.year = 0;
00344                     src->month = 1;
00345                     datetime_increment(src, &tinc);     /* no sign change */
00346                 }
00347                 else {          /* have to convert to days */
00348                     tinc.day = src->day - 1;    /* convert to REL */
00349                     for (i = src->month - 1; i > 0; i--) {
00350                         tinc.day +=
00351                             datetime_days_in_month(src->year, i,
00352                                                    src->positive);
00353                     }
00354                     tinc.hour = src->hour;
00355                     tinc.minute = src->minute;
00356                     tinc.second = src->second;
00357                     src->year = incr->year - src->year + 1;
00358                     /* +1 to skip 0 */
00359                     datetime_invert_sign(src);
00360                     src->month = 1;
00361                     src->day = 1;
00362                     src->hour = src->minute = 0;
00363                     src->second = 0;
00364                     datetime_increment(src, &tinc);     /* no sign change */
00365                 }
00366             }
00367             else
00368                 src->year -= incr->year;
00369             break;
00370         }
00371     }
00372 
00373     return 0;
00374 }
00375 
00376 /*****************************************************************/
00377 
00378 /* When absolute is zero, all fields carry toward the future */
00379 /* When absolute is one, sign of datetime is ignored */
00380 static int _datetime_carry(DateTime * dt, int absolute)
00381 {
00382     int i, carry;
00383 
00384     /* normalize day-sec (same for ABSOLUTE & RELATIVE) */
00385     for (i = dt->to; i > dt->from && i > DATETIME_DAY; i--) {
00386         switch (i) {
00387         case DATETIME_SECOND:
00388             if (dt->second >= 60.) {
00389                 carry = dt->second / 60.;
00390                 dt->minute += carry;
00391                 dt->second -= carry * 60;
00392             }
00393             break;
00394         case DATETIME_MINUTE:
00395             if (dt->minute >= 60) {
00396                 carry = dt->minute / 60;
00397                 dt->hour += carry;
00398                 dt->minute -= carry * 60;
00399             }
00400             break;
00401         case DATETIME_HOUR:
00402             if (dt->hour >= 24) {
00403                 carry = dt->hour / 24;
00404                 dt->day += carry;
00405                 dt->hour -= carry * 24;
00406             }
00407             break;
00408         }
00409     }
00410 
00411     /* give year a SIGN, temporarily */
00412     if (!absolute && !dt->positive && dt->mode == DATETIME_ABSOLUTE) {
00413         dt->year = -dt->year;
00414     }
00415 
00416     if (dt->from == DATETIME_YEAR && dt->to >= DATETIME_MONTH) {
00417 
00418         /* normalize yr-mo */
00419         if (dt->mode == DATETIME_ABSOLUTE) {
00420             if (dt->month > 12) {       /* month will never be zero */
00421                 carry = (dt->month - 1) / 12;   /* no carry until 13 */
00422                 dt->year += carry;
00423                 if (dt->year == 0)
00424                     dt->year = 1;
00425                 dt->month -= carry * 12;
00426                 /* 
00427                    if(dt->month == 0) dt->month = 1; 
00428                    shouldn't happen */
00429             }
00430         }
00431         else {
00432             if (dt->month >= 12) {
00433                 carry = dt->month / 12;
00434                 dt->year += carry;
00435                 dt->month -= carry * 12;
00436             }
00437         }
00438 
00439     }
00440 
00441     /* normalize yr-day */
00442     if (dt->mode == DATETIME_ABSOLUTE && dt->to > DATETIME_MONTH) {
00443 
00444         while (dt->day >
00445                datetime_days_in_month(dt->year, dt->month, dt->positive)) {
00446             dt->day -=
00447                 datetime_days_in_month(dt->year, dt->month, dt->positive);
00448             if (dt->month == 12) {      /* carry to year */
00449                 dt->year++;
00450                 if (dt->year == 0)
00451                     dt->year = 1;
00452                 dt->month = 1;
00453             }
00454             else                /* no carry to year */
00455                 dt->month++;
00456 
00457         }                       /* end while */
00458     }                           /* end if */
00459 
00460     /* undo giving year a SIGN, temporarily */
00461     if (!absolute && dt->mode == DATETIME_ABSOLUTE) {
00462         if (dt->year < 0) {
00463             dt->year = -dt->year;
00464             dt->positive = 0;
00465         }
00466         else
00467             dt->positive = 1;
00468     }
00469 
00470     return 0;
00471 }
00472 
00473 static int _datetime_add_field(DateTime * src, DateTime * incr, int field)
00474 {
00475     switch (field) {
00476     case DATETIME_SECOND:
00477         src->second += incr->second;
00478         break;
00479     case DATETIME_MINUTE:
00480         src->minute += incr->minute;
00481         break;
00482     case DATETIME_HOUR:
00483         src->hour += incr->hour;
00484         break;
00485     case DATETIME_DAY:
00486         src->day += incr->day;
00487         break;
00488     case DATETIME_MONTH:
00489         src->month += incr->month;
00490         break;
00491     case DATETIME_YEAR:
00492         src->year += incr->year;
00493         break;
00494     }
00495     if (src->mode == DATETIME_RELATIVE)
00496         _datetime_carry(src, 1);        /* do carries using absolute values */
00497     else
00498         _datetime_carry(src, 0);        /* do carries toward future */
00499 
00500     return 0;
00501 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines