123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- /*
- * Copyright (C) 1995. Bill Brown <brown@gis.uiuc.edu> & Michael Shapiro
- *
- * This program is free software under the GPL (>=v2)
- * Read the file GPL.TXT coming with GRASS for details.
- */
- #include <stdlib.h>
- #include <grass/datetime.h>
- #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(const DateTime *, double *);
- static int _datetime_compare(const DateTime *, const DateTime *);
- /*!
- * \brief
- *
- *
- * This performs the formula: result = a - b;
- * <ul>
- <li> both a and b must be absolute.
- * </li>
- <li> result will be relative
- * </li>
- <li> If a is "earlier" than b, then result will be set negative.
- * </li>
- <li> b must be no more "precise" than a.
- * (a copy of b is "extended" to the precision of a)
- * </li>
- <li> If result.to == SECOND, then result.fracsec is a.fracsec
- * </li>
- <li> 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]
- * </li>
- <li> If either 'a' or 'b' has a timezone, both must have a timezone. The
- * difference will account for the differences in the time zones.
- </li></ul>
- *
- * \param a
- * \param b
- * \param result
- * \return int
- */
- int
- datetime_difference(const DateTime * a, const 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(const DateTime * a, const 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(const 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;
- }
- /*************************************************************/
- /*************************************************************/
|