GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
diff.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1995. Bill Brown <brown@gis.uiuc.edu> & Michael Shapiro
3  *
4  * This program is free software under the GPL (>=v2)
5  * Read the file GPL.TXT coming with GRASS for details.
6  */
7 #include <stdlib.h>
8 #include <grass/datetime.h>
9 #include "math.h"
10 
11 /*************************************************************/
12 /*
13  This performs the formula: result = a - b;
14 
15  both a and b must be absolute.
16  result will be relative
17  If a is "earlier" than b, then result should be set negative.
18 
19  b must be no more "precise" than a.
20  (a copy of b is "extended" to the precision of a)
21 
22  datetime_copy (tb, b)
23  datetime_reset_from_to (tb, b.from, a.to, a.fracsec))
24 
25 
26  If result.to == SECOND, then result.fracsec is a.fracsec
27 
28  result will have the following from/to based on a.to:
29 
30  result
31  a.to from to
32  YEAR YEAR YEAR
33  MONTH YEAR MONTH
34  DAY DAY DAY
35  HOUR DAY HOUR
36  MINUTE DAY MINUTE
37  SECOND DAY SECOND
38 
39  If either 'a' or 'b' has a timezone, both must have a timezone.
40  The difference will account for the differences in the time zones.
41  */
42 
43 static int _datetime_ymd_to_ddays(const DateTime *, double *);
44 static int _datetime_compare(const DateTime *, const DateTime *);
45 
46 
47 /*!
48  * \brief
49  *
50  *
51  * This performs the formula: result = a - b;
52  * <ul>
53  <li> both a and b must be absolute.
54  * </li>
55  <li> result will be relative
56  * </li>
57  <li> If a is "earlier" than b, then result will be set negative.
58  * </li>
59  <li> b must be no more "precise" than a.
60  * (a copy of b is "extended" to the precision of a)
61  * </li>
62  <li> If result.to == SECOND, then result.fracsec is a.fracsec
63  * </li>
64  <li> result will have the following from/to based
65  * on a.to: result a.to from to YEAR YEAR YEAR MONTH YEAR
66  * MONTH DAY DAY DAY HOUR DAY HOUR MINUTE DAY
67  * MINUTE SECOND DAY SECOND [LAYOUT ??? - see HTML]
68  * </li>
69  <li> If either 'a' or 'b' has a timezone, both must have a timezone. The
70  * difference will account for the differences in the time zones.
71  </li></ul>
72 
73  *
74  * \param a
75  * \param b
76  * \param result
77  * \return int
78  */
79 
80 int
81 datetime_difference(const DateTime * a, const DateTime * b, DateTime * result)
82 {
83  DateTime tb, ta, *early, *late;
84  int compare, tzmin;
85 
86  /* if not both absolute, return error */
87 
88  datetime_copy(&tb, b);
90 
91  datetime_copy(&ta, a);
92  if (datetime_get_timezone(&ta, &tzmin) == 0 ||
93  datetime_get_timezone(&tb, &tzmin) == 0) {
94  if (datetime_get_timezone(&ta, &tzmin) == 0 &&
95  datetime_get_timezone(&tb, &tzmin) == 0) {
98  }
99  else
100  return datetime_error(-1,
101  "only one opperand contains valid timezone");
102  }
103 
104  /* initialize result */
107  ta.to, ta.fracsec);
108  compare = _datetime_compare(&ta, &tb);
109  if (compare > 0) {
110  early = &tb;
111  late = &ta;
112  result->positive = 1;
113  }
114  else if (compare < 0) {
115  early = &ta;
116  late = &tb;
117  result->positive = 0;
118  }
119  else { /* equal */
120  return (0);
121  }
122 
123  /* now the work */
125  int dm;
126 
127  if (ta.positive == tb.positive) {
128  /* change if we use doubles! */
129  result->year = abs(late->year - early->year);
130  }
131  else {
132  result->year = late->year + early->year - 2;
133  }
134  dm = late->month - early->month;
135  if (dm >= 0)
136  result->month = dm;
137  else {
138  result->year -= 1;
139  result->month = dm + 12;
140  }
141  }
142  else {
143  DateTime erel, lrel;
144  double latedays, earlydays;
145 
146  datetime_set_increment_type(a, &erel);
147  _datetime_ymd_to_ddays(early, &earlydays);
148  /* copy day -> down */
149  erel.day = earlydays;
150  erel.hour = early->hour;
151  erel.minute = early->minute;
152  erel.second = early->second;
153 
154  datetime_set_increment_type(a, &lrel);
155  _datetime_ymd_to_ddays(late, &latedays);
156  /* copy day -> down */
157  lrel.day = latedays;
158  lrel.hour = late->hour;
159  lrel.minute = late->minute;
160  lrel.second = late->second;
161 
162  datetime_invert_sign(&erel);
163  datetime_increment(&erel, &lrel);
164 
165  /* copy erel back to result */
166  result->day = erel.day;
167  result->hour = erel.hour;
168  result->minute = erel.minute;
169  result->second = erel.second;
170 
171  /* need carry? */
172  }
173 
174  return (0);
175 }
176 
177 /*************************************************************/
178 /* returns 1 if a is later than b,
179  -1 if a is earlier than a,
180  0 otherwise
181  */
182 /* only looks at from-to fields defined by a */
183 
184 static int _datetime_compare(const DateTime * a, const DateTime * b)
185 {
186  int i;
187 
188  if (a->positive && !b->positive)
189  return (1);
190  else if (b->positive && !a->positive)
191  return (-1);
192 
193  /* same signs */
194  for (i = a->from; i <= a->to; i++) {
195  switch (i) {
196 
197  case DATETIME_SECOND:
198  if (a->second > b->second)
199  return (1);
200  else if (a->second < b->second)
201  return (-1);
202  break;
203 
204  case DATETIME_MINUTE:
205  if (a->minute > b->minute)
206  return (1);
207  else if (a->minute < b->minute)
208  return (-1);
209  break;
210 
211  case DATETIME_HOUR:
212  if (a->hour > b->hour)
213  return (1);
214  else if (a->hour < b->hour)
215  return (-1);
216  break;
217 
218  case DATETIME_DAY:
219  if (a->day > b->day)
220  return (1);
221  else if (a->day < b->day)
222  return (-1);
223  break;
224 
225  case DATETIME_MONTH:
226  if (a->month > b->month)
227  return (1);
228  else if (a->month < b->month)
229  return (-1);
230  break;
231 
232  case DATETIME_YEAR: /* only place sign matters */
233  if (a->positive) {
234  if (a->year > b->year)
235  return (1);
236  else if (a->year < b->year)
237  return (-1);
238  }
239  else {
240  if (a->year < b->year)
241  return (1);
242  else if (a->year > b->year)
243  return (-1);
244  }
245  break;
246  }
247  }
248  return (0);
249 
250 
251 }
252 
253 /*************************************************************/
254 
255 static int _datetime_ymd_to_ddays(const DateTime * dtymd, double *days)
256 { /* note extra precision! */
257  int yr, mo;
258 
259 
260  *days = 0.0;
261 
262  if (dtymd->positive) {
263  *days = dtymd->day - 1; /* start w/ days - 1 */
264  for (mo = dtymd->month - 1; mo > 0; mo--) { /* add earlier months */
265  *days += datetime_days_in_month(dtymd->year, mo, dtymd->positive);
266  }
267  for (yr = dtymd->year - 1; yr > 0; yr--) { /* add earlier years */
268  *days += datetime_days_in_year(yr, dtymd->positive);
269  }
270  }
271  else {
272  for (yr = dtymd->year - 1; yr > 0; yr--) { /* add later years */
273  *days += datetime_days_in_year(yr, dtymd->positive);
274  }
275  for (mo = 12; mo >= dtymd->month; mo--) { /*add current & later months */
276  *days += datetime_days_in_month(dtymd->year, mo, dtymd->positive);
277  }
278  *days -= dtymd->day; /* subtract current days */
279  }
280 
281  return 0;
282 }
283 
284 /*************************************************************/
285 
286 /*************************************************************/
int hour
Definition: datetime.h:23
int datetime_get_timezone(const DateTime *dt, int *minutes)
returns 0 on success
Definition: tz1.c:49
#define DATETIME_SECOND
Definition: datetime.h:15
int day
Definition: datetime.h:22
double second
Definition: datetime.h:24
#define DATETIME_MONTH
Definition: datetime.h:11
int datetime_error(int code, char *msg)
record &#39;code&#39; and &#39;msg&#39; as error code/msg (in static variables) code==0 will clear the error (ie set ...
#define DATETIME_MINUTE
Definition: datetime.h:14
int from
Definition: datetime.h:20
#define DATETIME_RELATIVE
Definition: datetime.h:5
int year
Definition: datetime.h:22
#define DATETIME_YEAR
Definition: datetime.h:10
int positive
Definition: datetime.h:25
int datetime_change_to_utc(DateTime *dt)
Return datetime_change_timezone (dt, 0);.
Definition: tz2.c:63
void datetime_copy(DateTime *src, const DateTime *dst)
Copies the DateTime [into/from ???] src.
Definition: datetime/copy.c:20
void datetime_invert_sign(DateTime *dt)
Definition: sign.c:80
double b
Definition: r_raster.c:39
int fracsec
Definition: datetime.h:21
int datetime_days_in_year(int year, int ad)
returns the number of days in &#39;year&#39;
Definition: datetime/misc.c:41
int datetime_days_in_month(int year, int month, int ad)
returns number of days in &#39;month&#39; of a particular &#39;year&#39;
Definition: datetime/misc.c:64
#define DATETIME_DAY
Definition: datetime.h:12
int datetime_set_type(DateTime *dt, int mode, int from, int to, int fracsec)
Definition: datetime/type.c:37
int datetime_difference(const DateTime *a, const DateTime *b, DateTime *result)
This performs the formula: result = a - b;.
Definition: diff.c:81
int month
Definition: datetime.h:22
int datetime_set_increment_type(const DateTime *src, DateTime *incr)
src must be legal This is a convenience routine which is implemented as follows:
Definition: incr3.c:86
int compare(const void *a, const void *b)
Definition: dgraph.c:177
int to
Definition: datetime.h:20
int datetime_in_interval_year_month(int x)
int datetime_change_from_to(DateTime *dt, int from, int to, int round)
Changes the from/to of the type for dt. The &#39;from/to&#39; must be legal values for the mode of dt; (if th...
Definition: change.c:55
#define DATETIME_HOUR
Definition: datetime.h:13
int minute
Definition: datetime.h:23
int datetime_increment(DateTime *src, DateTime *incr)
This function changes the &#39;src&#39; date/time data based on the &#39;incr&#39; The type (mode/from/to) of the &#39;sr...
Definition: incr1.c:67