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