bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
DODS_Decimal_Year.cc
1
2// -*- mode: c++; c-basic-offset:4 -*-
3
4// This file is part of ff_handler a FreeForm API handler for the OPeNDAP
5// DAP2 data server.
6
7// Copyright (c) 2005 OPeNDAP, Inc.
8// Author: James Gallagher <jgallagher@opendap.org>
9//
10// This is free software; you can redistribute it and/or modify it under the
11// terms of the GNU Lesser General Public License as published by the Free
12// Software Foundation; either version 2.1 of the License, or (at your
13// option) any later version.
14//
15// This software is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18// License for more details.
19//
20// You should have received a copy of the GNU Lesser General Public
21// License along with this library; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23//
24// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25
26// (c) COPYRIGHT URI/MIT 1998
27// Please read the full copyright statement in the file COPYRIGHT.
28//
29// Authors:
30// jhrg,jimg James Gallagher (jgallagher@gso.uri.edu)
31// danh Dan Holloway (dholloway@gso.uri.edu)
32//
33// Implementation of the DODS Decimal_Year class
34
35#include "config_ff.h"
36
37static char rcsid[] not_used ="$Id$";
38
39
40#include <time.h>
41
42#include <cassert>
43#include <cstdlib>
44#include <sstream>
45
46#include <libdap/Error.h>
47#include "DODS_Decimal_Year.h"
48#include "date_proc.h"
49#include <libdap/debug.h>
50
51#define seconds_per_day 86400.0
52#define seconds_per_hour 3600.0
53#define seconds_per_minute 60.0
54
55static string
56extract_argument(BaseType *arg)
57{
58#ifndef TEST
59 if (arg->type() != dods_str_c)
60 throw Error(malformed_expr,
61 "The Projection function requires a DODS string-type argument.");
62
63 // Use string until conversion of string to string is complete. 9/3/98
64 // jhrg
65 string *sp = NULL;
66 arg->buf2val((void **)&sp);
67 string s = sp->c_str();
68 delete sp;
69
70 DBG(cerr << "s: " << s << endl);
71
72 return s;
73#else
74 return "";
75#endif
76}
77
78// Public mfuncs
79
80bool
82{
83 return _date.OK();
84}
85
89
91{
92}
93
95{
96 set(date_time);
97}
98
100{
101 set(date_time);
102}
103
104DODS_Decimal_Year::DODS_Decimal_Year(int y, int m, int d, int hh, int mm,
105 double ss, bool gmt)
106{
107 set(y, m, d, hh, mm, ss, gmt);
108}
109
110DODS_Decimal_Year::DODS_Decimal_Year(int y, int yd, int hh, int mm, double ss,
111 bool gmt)
112{
113 set(y, yd, hh, mm, ss, gmt);
114}
115
116void
118{
119 _date = d;
120
121 assert(OK());
122}
123
124void
126{
127 _date = d;
128 _time = t;
129
130 assert(OK());
131}
132
133void
135{
136 double secs_in_year, days_in_year;
137 double d_year_day, d_hr_day, d_min_day, d_sec_day;
138 int i_year, i_year_day, i_hr_day, i_min_day, i_sec_day;
139
140 // The format for the decimal-year string is <year part>.<fraction part>.
141
142 double d_year = strtod(dec_year.c_str(), 0);
143
144 i_year = d_year * 1;
145 double year_fraction = d_year - i_year;
146
147 days_in_year = days_in_year(i_year);
148 secs_in_year = days_in_year * seconds_per_day;
149
150 //
151 // Recreate the 'day' in the year.
152 //
153 d_year_day = (secs_in_year * year_fraction)/seconds_per_day + 1;
154 i_year_day = d_year_day * 1;
155
156 //
157 // Recreate the 'hour' in the day.
158 //
159 d_hr_day = ((d_year_day - i_year_day)*seconds_per_day) / seconds_per_hour;
160 i_hr_day = d_hr_day * 1;
161
162 //
163 // Recreate the 'minute' in the hour.
164 //
165 d_min_day = ((d_hr_day - i_hr_day)*seconds_per_hour) / seconds_per_minute;
166 i_min_day = d_min_day * 1;
167
168 //
169 // Recreate the 'second' in the minute.
170 //
171 d_sec_day = (d_min_day - i_min_day)*seconds_per_minute;
172 i_sec_day = d_sec_day * 1;
173
174 //
175 // Round-off second to nearest value, handle condition
176 // where seconds/minutes roll over modulo values.
177 //
178 if ((d_sec_day - i_sec_day) >= .5) i_sec_day++;
179
180 if ( i_sec_day == 60 ) {
181 i_sec_day = 0;
182 i_min_day++;
183 if ( i_min_day == 60 ) {
184 i_min_day = 0;
185 i_hr_day++;
186 if ( i_hr_day == 24 ) {
187 i_hr_day = 0;
188 i_year_day++;
189 if ( i_year_day == (days_in_year+1)) {
190 i_year_day = 1;
191 i_year++;
192 }
193 }
194 }
195 }
196
197 _date.set((int)i_year, (int)i_year_day);
198 _time.set((int)i_hr_day, (int)i_min_day, (double)i_sec_day);
199
200 assert(OK());
201}
202
203void
204DODS_Decimal_Year::set(BaseType *date_time)
205{
206 set(extract_argument(date_time));
207}
208
209void
210DODS_Decimal_Year::set(int y, int m, int d, int hh, int mm, double ss, bool gmt)
211{
212 _date.set(y, m, d);
213 _time.set(hh, mm, ss, gmt);
214
215 assert(OK());
216}
217
218void
219DODS_Decimal_Year::set(int y, int yd, int hh, int mm, double ss, bool gmt)
220{
221 _date.set(y, yd);
222 _time.set(hh, mm, ss, gmt);
223
224 assert(OK());
225}
226
227int
229{
230 return _date.year();
231}
232
233int
235{
236 int yr = _date.year();
237
238 if ( (yr % 4 == 0) && ((yr % 100 != 0) || (yr % 400 == 0)) ) return 366;
239 else return 365;
240}
241
242double
244{
245 double decimal_day;
246 double day_number, hrs, min, sec, days_in;
247
248 day_number = (double)_date.day_number();
249 hrs = (double)_time.hours();
250 min = (double)_time.minutes();
251 sec = (double)_time.seconds();
252 days_in = (double)days_in_year();
253
254 decimal_day = (day_number-1+((hrs+((min+(sec/60.0))/60.0))/24.0))/days_in;
255
256 return decimal_day;
257}
258
259bool
261{
262 return _time.gmt();
263}
264
265string
266DODS_Decimal_Year::get(date_format format, bool gmt) const
267{
268 ostringstream oss;
269 oss.precision(14);
270
271 double decday = (double)_date.year() + fraction();
272
273 oss << decday;
274
275 return oss.str()
276}
277
278double
280{
281 return _date.julian_day() + _time.seconds_since_midnight()/seconds_per_day;
282}
283
284time_t
286{
287 struct tm tm_rec{};
288 tm_rec.tm_mday = _date.day();
289 tm_rec.tm_mon = _date.month() - 1; // zero-based
290 tm_rec.tm_year = _date.year() - 1900; // years since 1900
291 tm_rec.tm_hour = _time.hours();
292 tm_rec.tm_min = _time.minutes();
293 tm_rec.tm_sec = (int)_time.seconds();
294 tm_rec.tm_isdst = -1;
295
296 return mktime(&tm_rec);
297}
298
299double
301{
302 return _time.get_epsilon();
303}
304
305void
307{
308 _time.set_epsilon(eps);
309}
310
311int
313{
314 return t1._date == t2._date && t1._time == t2._time;
315}
316
317int
319{
320 return t1._date != t2._date || t1._time != t2._time;
321}
322
323int
325{
326 return t1._date < t2._date
327 || (t1._date == t2._date && t1._time < t2._time);
328}
329
330int
332{
333 return t1._date > t2._date
334 || (t1._date == t2._date && t1._time > t2._time);
335}
336
337int
339{
340 return t1 == t2 || t1 < t2;
341}
342
343int
345{
346 return t1 == t2 || t1 > t2;
347}
348
349#ifdef DECIMAL_YEAR_TEST
350
351/* Input args: 1 string,
352 2 Two strings,
353 5 y, yd, hh, mm, ss,
354 6 y, m, d, hh, mm, ss
355
356 Compile using: g++ -g -I../../include -DHAVE_CONFIG_H -DTEST
357 -DDECIMAL_YEAR_TEST DODS_Date.cc DODS_Time.cc DODS_Decimal_Year.cc date_proc.cc
358 -lg++
359*/
360
361int
362main(int argc, char *argv[])
363{
364
366 DODS_Decimal_Year dt2("1970/1/1:0:0:0");
367 argc--;
368 switch(argc) {
369 case 1:
370 dt.set(argv[1]);
371 break;
372 case 2:
373 dt.set(argv[1]);
374 dt2.set(argv[2]);
375 break;
376 case 5:
377 dt.set(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]),
378 atoi(argv[4]), atof(argv[5]));
379 break;
380 case 6:
381 dt.set(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]),
382 atoi(argv[4]), atoi(argv[5]), atof(argv[6]));
383 break;
384 default:
385 cerr << "Wrong number of arguments!" << endl;
386 exit(1);
387 }
388
389 if (dt < dt2)
390 cout << "True: dt < dt2" << endl;
391 else
392 cout << "False: dt < dt2" << endl;
393
394 if (dt > dt2)
395 cout << "True: dt > dt2" << endl;
396 else
397 cout << "False: dt > dt2" << endl;
398
399 if (dt <= dt2)
400 cout << "True: dt <= dt2" << endl;
401 else
402 cout << "False: dt <= dt2" << endl;
403
404 if (dt >= dt2)
405 cout << "True: dt >= dt2" << endl;
406 else
407 cout << "False: dt >= dt2" << endl;
408
409 if (dt == dt2)
410 cout << "True: dt == dt2" << endl;
411 else
412 cout << "False: dt == dt2" << endl;
413
414 if (dt != dt2)
415 cout << "True: dt != dt2" << endl;
416 else
417 cout << "False: dt != dt2" << endl;
418
419 // cout << "YMD: " << dt.ymd() << endl;
420 //cout << "YD: " << dt.yd() << endl;
421 cout << "Julian day: " << dt.julian_day() << endl;
422 cout << "Seconds: " << dt.unix_time() << endl;
423}
424#endif // TEST_DATE
425
friend int operator==(DODS_Decimal_Year &t1, DODS_Decimal_Year &t2)
Equality.
friend int operator<=(DODS_Decimal_Year &t1, DODS_Decimal_Year &t2)
Less-than or Equal-to.
friend int operator!=(DODS_Decimal_Year &t1, DODS_Decimal_Year &t2)
Inequality.
string get(date_format format=ymd, bool gmt=true) const
friend int operator>=(DODS_Decimal_Year &t1, DODS_Decimal_Year &t2)
Greater-than or Equal-to.
double get_epsilon() const
double fraction() const
friend int operator<(DODS_Decimal_Year &t1, DODS_Decimal_Year &t2)
Less-than.
friend int operator>(DODS_Decimal_Year &t1, DODS_Decimal_Year &t2)
Greater-than.
time_t unix_time() const
void set(DODS_Date d)
void set_epsilon(double eps)
double julian_day() const
STL class.