GRASS Programmer's Manual
6.4.2(2012)
|
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 /*************************************************************/