GRASS Programmer's Manual  6.4.2(2012)
diff.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 <stdlib.h>
00008 #include <grass/datetime.h>
00009 #include "math.h"
00010 
00011 /*************************************************************/
00012 /*
00013    This performs the formula:   result = a - b;
00014 
00015    both a and b must be absolute.
00016    result will be relative
00017    If a is "earlier" than b, then result should be set negative.
00018 
00019    b must be no more "precise" than a.
00020    (a copy of b is "extended" to the precision of a)
00021 
00022    datetime_copy (tb, b)
00023    datetime_reset_from_to (tb, b.from, a.to, a.fracsec))
00024 
00025 
00026    If result.to == SECOND, then result.fracsec is a.fracsec
00027 
00028    result will have the following from/to based on a.to:
00029 
00030    result
00031    a.to      from    to
00032    YEAR      YEAR    YEAR
00033    MONTH     YEAR    MONTH
00034    DAY       DAY     DAY
00035    HOUR      DAY     HOUR
00036    MINUTE    DAY     MINUTE
00037    SECOND    DAY     SECOND
00038 
00039    If either 'a' or 'b' has a timezone, both must have a timezone.
00040    The difference will account for the differences in the time zones.
00041  */
00042 
00043 static int _datetime_ymd_to_ddays(const DateTime *, double *);
00044 static int _datetime_compare(const DateTime *, const DateTime *);
00045 
00046 
00080 int
00081 datetime_difference(const DateTime * a, const DateTime * b, DateTime * result)
00082 {
00083     DateTime tb, ta, *early, *late;
00084     int compare, tzmin;
00085 
00086     /* if not both absolute, return error */
00087 
00088     datetime_copy(&tb, b);
00089     datetime_change_from_to(&tb, DATETIME_YEAR, a->to, a->fracsec);
00090 
00091     datetime_copy(&ta, a);
00092     if (datetime_get_timezone(&ta, &tzmin) == 0 ||
00093         datetime_get_timezone(&tb, &tzmin) == 0) {
00094         if (datetime_get_timezone(&ta, &tzmin) == 0 &&
00095             datetime_get_timezone(&tb, &tzmin) == 0) {
00096             datetime_change_to_utc(&ta);
00097             datetime_change_to_utc(&tb);
00098         }
00099         else
00100             return datetime_error(-1,
00101                                   "only one opperand contains valid timezone");
00102     }
00103 
00104     /* initialize result */
00105     datetime_set_type(result, DATETIME_RELATIVE,
00106                       ta.to < DATETIME_DAY ? DATETIME_YEAR : DATETIME_DAY,
00107                       ta.to, ta.fracsec);
00108     compare = _datetime_compare(&ta, &tb);
00109     if (compare > 0) {
00110         early = &tb;
00111         late = &ta;
00112         result->positive = 1;
00113     }
00114     else if (compare < 0) {
00115         early = &ta;
00116         late = &tb;
00117         result->positive = 0;
00118     }
00119     else {                      /* equal */
00120         return (0);
00121     }
00122 
00123     /* now the work */
00124     if (datetime_in_interval_year_month(ta.to)) {
00125         int dm;
00126 
00127         if (ta.positive == tb.positive) {
00128             /* change if we use doubles! */
00129             result->year = abs(late->year - early->year);
00130         }
00131         else {
00132             result->year = late->year + early->year - 2;
00133         }
00134         dm = late->month - early->month;
00135         if (dm >= 0)
00136             result->month = dm;
00137         else {
00138             result->year -= 1;
00139             result->month = dm + 12;
00140         }
00141     }
00142     else {
00143         DateTime erel, lrel;
00144         double latedays, earlydays;
00145 
00146         datetime_set_increment_type(a, &erel);
00147         _datetime_ymd_to_ddays(early, &earlydays);
00148         /* copy day -> down */
00149         erel.day = earlydays;
00150         erel.hour = early->hour;
00151         erel.minute = early->minute;
00152         erel.second = early->second;
00153 
00154         datetime_set_increment_type(a, &lrel);
00155         _datetime_ymd_to_ddays(late, &latedays);
00156         /* copy day -> down */
00157         lrel.day = latedays;
00158         lrel.hour = late->hour;
00159         lrel.minute = late->minute;
00160         lrel.second = late->second;
00161 
00162         datetime_invert_sign(&erel);
00163         datetime_increment(&erel, &lrel);
00164 
00165         /* copy erel back to result */
00166         result->day = erel.day;
00167         result->hour = erel.hour;
00168         result->minute = erel.minute;
00169         result->second = erel.second;
00170 
00171         /* need carry? */
00172     }
00173 
00174     return (0);
00175 }
00176 
00177 /*************************************************************/
00178 /* returns 1 if a is later than b, 
00179    -1 if a is earlier than a,
00180    0 otherwise 
00181  */
00182 /* only looks at from-to fields defined by a */
00183 
00184 static int _datetime_compare(const DateTime * a, const DateTime * b)
00185 {
00186     int i;
00187 
00188     if (a->positive && !b->positive)
00189         return (1);
00190     else if (b->positive && !a->positive)
00191         return (-1);
00192 
00193     /* same signs */
00194     for (i = a->from; i <= a->to; i++) {
00195         switch (i) {
00196 
00197         case DATETIME_SECOND:
00198             if (a->second > b->second)
00199                 return (1);
00200             else if (a->second < b->second)
00201                 return (-1);
00202             break;
00203 
00204         case DATETIME_MINUTE:
00205             if (a->minute > b->minute)
00206                 return (1);
00207             else if (a->minute < b->minute)
00208                 return (-1);
00209             break;
00210 
00211         case DATETIME_HOUR:
00212             if (a->hour > b->hour)
00213                 return (1);
00214             else if (a->hour < b->hour)
00215                 return (-1);
00216             break;
00217 
00218         case DATETIME_DAY:
00219             if (a->day > b->day)
00220                 return (1);
00221             else if (a->day < b->day)
00222                 return (-1);
00223             break;
00224 
00225         case DATETIME_MONTH:
00226             if (a->month > b->month)
00227                 return (1);
00228             else if (a->month < b->month)
00229                 return (-1);
00230             break;
00231 
00232         case DATETIME_YEAR:     /* only place sign matters */
00233             if (a->positive) {
00234                 if (a->year > b->year)
00235                     return (1);
00236                 else if (a->year < b->year)
00237                     return (-1);
00238             }
00239             else {
00240                 if (a->year < b->year)
00241                     return (1);
00242                 else if (a->year > b->year)
00243                     return (-1);
00244             }
00245             break;
00246         }
00247     }
00248     return (0);
00249 
00250 
00251 }
00252 
00253 /*************************************************************/
00254 
00255 static int _datetime_ymd_to_ddays(const DateTime * dtymd, double *days)
00256 {                               /* note extra precision! */
00257     int yr, mo;
00258 
00259 
00260     *days = 0.0;
00261 
00262     if (dtymd->positive) {
00263         *days = dtymd->day - 1; /* start w/ days - 1 */
00264         for (mo = dtymd->month - 1; mo > 0; mo--) {     /* add earlier months */
00265             *days += datetime_days_in_month(dtymd->year, mo, dtymd->positive);
00266         }
00267         for (yr = dtymd->year - 1; yr > 0; yr--) {      /* add earlier years */
00268             *days += datetime_days_in_year(yr, dtymd->positive);
00269         }
00270     }
00271     else {
00272         for (yr = dtymd->year - 1; yr > 0; yr--) {      /* add later years */
00273             *days += datetime_days_in_year(yr, dtymd->positive);
00274         }
00275         for (mo = 12; mo >= dtymd->month; mo--) {       /*add current & later months */
00276             *days += datetime_days_in_month(dtymd->year, mo, dtymd->positive);
00277         }
00278         *days -= dtymd->day;    /* subtract current days */
00279     }
00280 
00281     return 0;
00282 }
00283 
00284 /*************************************************************/
00285 
00286 /*************************************************************/
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines