GRASS 8 Programmer's Manual  8.5.0dev(2025)-c070206eb1
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 int datetime_difference(const DateTime *a, const DateTime *b, DateTime *result)
79 {
80  DateTime tb, ta, *early, *late;
81  int compare, tzmin;
82 
83  /* if not both absolute, return error */
84 
85  datetime_copy(&tb, b);
87 
88  datetime_copy(&ta, a);
89  if (datetime_get_timezone(&ta, &tzmin) == 0 ||
90  datetime_get_timezone(&tb, &tzmin) == 0) {
91  if (datetime_get_timezone(&ta, &tzmin) == 0 &&
92  datetime_get_timezone(&tb, &tzmin) == 0) {
95  }
96  else
97  return datetime_error(-1,
98  "only one opperand contains valid timezone");
99  }
100 
101  /* initialize result */
104  ta.to, ta.fracsec);
105  compare = _datetime_compare(&ta, &tb);
106  if (compare > 0) {
107  early = &tb;
108  late = &ta;
109  result->positive = 1;
110  }
111  else if (compare < 0) {
112  early = &ta;
113  late = &tb;
114  result->positive = 0;
115  }
116  else { /* equal */
117  return (0);
118  }
119 
120  /* now the work */
122  int dm;
123 
124  if (ta.positive == tb.positive) {
125  /* change if we use doubles! */
126  result->year = abs(late->year - early->year);
127  }
128  else {
129  result->year = late->year + early->year - 2;
130  }
131  dm = late->month - early->month;
132  if (dm >= 0)
133  result->month = dm;
134  else {
135  result->year -= 1;
136  result->month = dm + 12;
137  }
138  }
139  else {
140  DateTime erel, lrel;
141  double latedays, earlydays;
142 
143  datetime_set_increment_type(a, &erel);
144  _datetime_ymd_to_ddays(early, &earlydays);
145  /* copy day -> down */
146  erel.day = earlydays;
147  erel.hour = early->hour;
148  erel.minute = early->minute;
149  erel.second = early->second;
150 
151  datetime_set_increment_type(a, &lrel);
152  _datetime_ymd_to_ddays(late, &latedays);
153  /* copy day -> down */
154  lrel.day = latedays;
155  lrel.hour = late->hour;
156  lrel.minute = late->minute;
157  lrel.second = late->second;
158 
159  datetime_invert_sign(&erel);
160  datetime_increment(&erel, &lrel);
161 
162  /* copy erel back to result */
163  result->day = erel.day;
164  result->hour = erel.hour;
165  result->minute = erel.minute;
166  result->second = erel.second;
167 
168  /* need carry? */
169  }
170 
171  return (0);
172 }
173 
174 /*************************************************************/
175 /* returns 1 if a is later than b,
176  -1 if a is earlier than a,
177  0 otherwise
178  */
179 /* only looks at from-to fields defined by a */
180 
181 static int _datetime_compare(const DateTime *a, const DateTime *b)
182 {
183  int i;
184 
185  if (a->positive && !b->positive)
186  return (1);
187  else if (b->positive && !a->positive)
188  return (-1);
189 
190  /* same signs */
191  for (i = a->from; i <= a->to; i++) {
192  switch (i) {
193 
194  case DATETIME_SECOND:
195  if (a->second > b->second)
196  return (1);
197  else if (a->second < b->second)
198  return (-1);
199  break;
200 
201  case DATETIME_MINUTE:
202  if (a->minute > b->minute)
203  return (1);
204  else if (a->minute < b->minute)
205  return (-1);
206  break;
207 
208  case DATETIME_HOUR:
209  if (a->hour > b->hour)
210  return (1);
211  else if (a->hour < b->hour)
212  return (-1);
213  break;
214 
215  case DATETIME_DAY:
216  if (a->day > b->day)
217  return (1);
218  else if (a->day < b->day)
219  return (-1);
220  break;
221 
222  case DATETIME_MONTH:
223  if (a->month > b->month)
224  return (1);
225  else if (a->month < b->month)
226  return (-1);
227  break;
228 
229  case DATETIME_YEAR: /* only place sign matters */
230  if (a->positive) {
231  if (a->year > b->year)
232  return (1);
233  else if (a->year < b->year)
234  return (-1);
235  }
236  else {
237  if (a->year < b->year)
238  return (1);
239  else if (a->year > b->year)
240  return (-1);
241  }
242  break;
243  }
244  }
245  return (0);
246 }
247 
248 /*************************************************************/
249 
250 static int _datetime_ymd_to_ddays(const DateTime *dtymd, double *days)
251 { /* note extra precision! */
252  int yr, mo;
253 
254  *days = 0.0;
255 
256  if (dtymd->positive) {
257  *days = dtymd->day - 1; /* start w/ days - 1 */
258  for (mo = dtymd->month - 1; mo > 0; mo--) { /* add earlier months */
259  *days += datetime_days_in_month(dtymd->year, mo, dtymd->positive);
260  }
261  for (yr = dtymd->year - 1; yr > 0; yr--) { /* add earlier years */
262  *days += datetime_days_in_year(yr, dtymd->positive);
263  }
264  }
265  else {
266  for (yr = dtymd->year - 1; yr > 0; yr--) { /* add later years */
267  *days += datetime_days_in_year(yr, dtymd->positive);
268  }
269  for (mo = 12; mo >= dtymd->month;
270  mo--) { /*add current & later months */
271  *days += datetime_days_in_month(dtymd->year, mo, dtymd->positive);
272  }
273  *days -= dtymd->day; /* subtract current days */
274  }
275 
276  return 0;
277 }
278 
279 /*************************************************************/
280 
281 /*************************************************************/
#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:57
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:44
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:58
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:71
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:67
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:53
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:82
int datetime_days_in_year(int year, int ad)
returns the number of days in 'year'
Definition: datetime/misc.c:37
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:19
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:78
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