/* * Copyright (C) 1995. Bill Brown & Michael Shapiro * * This program is free software under the GPL (>=v2) * Read the file GPL.TXT coming with GRASS for details. */ #include #include #include "math.h" /*************************************************************/ /* This performs the formula: result = a - b; both a and b must be absolute. result will be relative If a is "earlier" than b, then result should be set negative. b must be no more "precise" than a. (a copy of b is "extended" to the precision of a) datetime_copy (tb, b) datetime_reset_from_to (tb, b.from, a.to, a.fracsec)) If result.to == SECOND, then result.fracsec is a.fracsec result will have the following from/to based on a.to: result a.to from to YEAR YEAR YEAR MONTH YEAR MONTH DAY DAY DAY HOUR DAY HOUR MINUTE DAY MINUTE SECOND DAY SECOND If either 'a' or 'b' has a timezone, both must have a timezone. The difference will account for the differences in the time zones. */ static int _datetime_ymd_to_ddays(DateTime *, double *); static int _datetime_compare(DateTime *,DateTime *); /*! * \brief * * * This performs the formula: result = a - b; *
  • both a and b must be absolute. *
  • result will be relative *
  • If a is "earlier" than b, then result will be set negative. *
  • b must be no more "precise" than a. * (a copy of b is "extended" to the precision of a) *
  • If result.to == SECOND, then result.fracsec is a.fracsec *
  • result will have the following from/to based * on a.to: result a.to from to YEAR YEAR YEAR MONTH YEAR * MONTH DAY DAY DAY HOUR DAY HOUR MINUTE DAY * MINUTE SECOND DAY SECOND [LAYOUT ??? - see HTML] *
  • If either 'a' or 'b' has a timezone, both must have a timezone. The * difference will account for the differences in the time zones.
* * \param a * \param b * \param result * \return int */ int datetime_difference (DateTime *a,DateTime *b,DateTime *result) { DateTime tb, ta, *early, *late; int compare, tzmin; /* if not both absolute, return error */ datetime_copy (&tb, b); datetime_change_from_to (&tb, DATETIME_YEAR, a->to, a->fracsec); datetime_copy (&ta, a); if(datetime_get_timezone (&ta, &tzmin) == 0 || datetime_get_timezone (&tb, &tzmin) == 0){ if(datetime_get_timezone (&ta, &tzmin) == 0 && datetime_get_timezone (&tb, &tzmin) == 0){ datetime_change_to_utc (&ta); datetime_change_to_utc (&tb); } else return datetime_error (-1, "only one opperand contains valid timezone"); } /* initialize result */ datetime_set_type(result, DATETIME_RELATIVE, ta.to < DATETIME_DAY? DATETIME_YEAR: DATETIME_DAY, ta.to, ta.fracsec); compare = _datetime_compare(&ta, &tb); if(compare > 0){ early = &tb; late = &ta; result->positive = 1; } else if(compare < 0){ early = &ta; late = &tb; result->positive = 0; } else{ /* equal */ return(0); } /* now the work */ if(datetime_in_interval_year_month (ta.to)){ int dm; if(ta.positive == tb.positive){ /* change if we use doubles! */ result->year = abs(late->year - early->year); } else{ result->year = late->year + early->year - 2; } dm = late->month - early->month; if(dm >= 0) result->month = dm; else{ result->year -= 1; result->month = dm + 12; } } else{ DateTime erel, lrel; double latedays, earlydays; datetime_set_increment_type(a, &erel); _datetime_ymd_to_ddays(early, &earlydays); /* copy day -> down */ erel.day = earlydays; erel.hour = early->hour; erel.minute = early->minute; erel.second = early->second; datetime_set_increment_type(a, &lrel); _datetime_ymd_to_ddays(late, &latedays); /* copy day -> down */ lrel.day = latedays; lrel.hour = late->hour; lrel.minute = late->minute; lrel.second = late->second; datetime_invert_sign(&erel); datetime_increment(&erel, &lrel); /* copy erel back to result */ result->day = erel.day; result->hour = erel.hour; result->minute = erel.minute; result->second = erel.second; /* need carry? */ } return(0); } /*************************************************************/ /* returns 1 if a is later than b, -1 if a is earlier than a, 0 otherwise */ /* only looks at from-to fields defined by a */ static int _datetime_compare(DateTime *a,DateTime *b) { int i; if(a->positive && !b->positive) return(1); else if(b->positive && !a->positive) return(-1); /* same signs */ for(i = a->from; i <= a->to; i++){ switch(i){ case DATETIME_SECOND: if(a->second > b->second) return(1); else if(a->second < b->second) return(-1); break; case DATETIME_MINUTE: if(a->minute > b->minute) return(1); else if(a->minute < b->minute) return(-1); break; case DATETIME_HOUR: if(a->hour > b->hour) return(1); else if(a->hour < b->hour) return(-1); break; case DATETIME_DAY: if(a->day > b->day) return(1); else if(a->day < b->day) return(-1); break; case DATETIME_MONTH: if(a->month > b->month) return(1); else if(a->month < b->month) return(-1); break; case DATETIME_YEAR: /* only place sign matters */ if(a->positive){ if(a->year > b->year) return(1); else if(a->year < b->year) return(-1); } else{ if(a->year < b->year) return(1); else if(a->year > b->year) return(-1); } break; } } return(0); } /*************************************************************/ static int _datetime_ymd_to_ddays( DateTime *dtymd, double *days) /* note extra precision! */ { int yr, mo; *days = 0.0; if(dtymd->positive){ *days = dtymd->day - 1; /* start w/ days - 1*/ for (mo = dtymd->month - 1; mo > 0; mo--){ /* add earlier months */ *days += datetime_days_in_month(dtymd->year, mo, dtymd->positive); } for (yr = dtymd->year - 1; yr > 0; yr--){ /* add earlier years */ *days += datetime_days_in_year(yr, dtymd->positive); } } else{ for (yr = dtymd->year - 1; yr > 0; yr--){ /* add later years */ *days += datetime_days_in_year(yr, dtymd->positive); } for (mo = 12; mo >= dtymd->month; mo--){ /*add current & later months*/ *days += datetime_days_in_month(dtymd->year, mo, dtymd->positive); } *days -= dtymd->day; /* subtract current days */ } return 0; } /*************************************************************/ /*************************************************************/