GRASS GIS 8 Programmer's Manual 8.4.1(2025)-45ca3179ab
Loading...
Searching...
No Matches
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
43static int _datetime_ymd_to_ddays(const DateTime *, double *);
44static 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
79int 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);
87 datetime_change_from_to(&tb, DATETIME_YEAR, a->to, a->fracsec);
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 */
103 datetime_set_type(result, DATETIME_RELATIVE,
104 ta.to < DATETIME_DAY ? DATETIME_YEAR : DATETIME_DAY,
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
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
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
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
182static 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
251static 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/*************************************************************/
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
void datetime_copy(DateTime *dst, const DateTime *src)
Copies the DateTime [into/from ???] src.
Definition copy.c:20
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_difference(const DateTime *a, const DateTime *b, DateTime *result)
This performs the formula: result = a - b;.
Definition diff.c:79
double b
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_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_month(int year, int month, int ad)
returns number of days in 'month' of a particular 'year'
Definition misc.c:61
int datetime_days_in_year(int year, int ad)
returns the number of days in 'year'
Definition misc.c:39
void datetime_invert_sign(DateTime *dt)
Definition sign.c:76
int datetime_set_type(DateTime *dt, int mode, int from, int to, int fracsec)
Definition type.c:36
int datetime_in_interval_year_month(int x)
Definition type.c:147
int datetime_get_timezone(const DateTime *dt, int *minutes)
returns 0 on success
Definition tz1.c:46
int datetime_change_to_utc(DateTime *dt)
Return datetime_change_timezone (dt, 0);.
Definition tz2.c:59