bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
DODS_Date_Time.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
32//
33// Implementation of the DODS Date/Time 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#include <string>
46
47#include <libdap/Error.h>
48#include "DODS_Date_Time.h"
49#include "date_proc.h"
50#include <libdap/debug.h>
51
52using namespace std;
53
54#define seconds_per_day 86400.0
55
56using namespace std;
57
58static string
59extract_argument(BaseType *arg)
60{
61#ifndef TEST
62 if (arg->type() != dods_str_c)
63 throw Error(malformed_expr,
64 "The Projection function requires a DODS string-type argument.");
65
66 // Use String until conversion of String to string is complete. 9/3/98
67 // jhrg
68 string *sp = NULL;
69 arg->buf2val((void **)&sp);
70 string s = sp->c_str();
71 delete sp;
72
73 DBG(cerr << "s: " << s << endl);
74
75 return s;
76#else
77 return "";
78#endif
79}
80
81// Public mfuncs
82
83bool
85{
86 return _time.OK() && _date.OK();
87}
88
92
93
95{
96}
97
99{
100 set(date_time);
101}
102
104{
105 set(date_time);
106}
107
108DODS_Date_Time::DODS_Date_Time(int y, int m, int d, int hh, int mm,
109 double ss, bool gmt)
110{
111 set(y, m, d, hh, mm, ss, gmt);
112}
113
114DODS_Date_Time::DODS_Date_Time(int y, int yd, int hh, int mm, double ss,
115 bool gmt)
116{
117 set(y, yd, hh, mm, ss, gmt);
118}
119
120void
122{
123 _date = d;
124 _time = t;
125
126 assert(OK());
127}
128
129// Ripped off from Dan's DODS_Decimal_Year code. 5/29/99 jhrg
130
131void
132DODS_Date_Time::parse_fractional_time(string dec_year)
133{
134 double secs_in_year;
135 double d_year_day, d_hr_day, d_min_day, d_sec_day;
136 int i_year, i_year_day, i_hr_day, i_min_day, i_sec_day;
137
138 // The format for the decimal-year string is <year part>.<fraction part>.
139
140 double d_year = strtod(dec_year.c_str(), 0);
141
142 i_year = (int)d_year;
143 double year_fraction = d_year - i_year;
144
145 secs_in_year = days_in_year(i_year) * seconds_per_day;
146
147 //
148 // Recreate the 'day' in the year.
149 //
150 d_year_day = (secs_in_year * year_fraction)/seconds_per_day + 1;
151 i_year_day = (int)d_year_day;
152
153 //
154 // Recreate the 'hour' in the day.
155 //
156 d_hr_day = ((d_year_day - i_year_day)*seconds_per_day) / seconds_per_hour;
157 i_hr_day = (int)d_hr_day;
158
159 //
160 // Recreate the 'minute' in the hour.
161 //
162 d_min_day = ((d_hr_day - i_hr_day)*seconds_per_hour) / seconds_per_minute;
163 i_min_day = (int)d_min_day;
164
165 //
166 // Recreate the 'second' in the minute.
167 //
168 d_sec_day = (d_min_day - i_min_day)*seconds_per_minute;
169 i_sec_day = (int)d_sec_day;
170
171 //
172 // Round-off second to nearest value, handle condition
173 // where seconds/minutes roll over modulo values.
174 //
175 if ((d_sec_day - i_sec_day) >= .5) i_sec_day++;
176
177 if ( i_sec_day == 60 ) {
178 i_sec_day = 0;
179 i_min_day++;
180 if ( i_min_day == 60 ) {
181 i_min_day = 0;
182 i_hr_day++;
183 if ( i_hr_day == 24 ) {
184 i_hr_day = 0;
185 i_year_day++;
186 if ( i_year_day == (days_in_year(i_year) + 1)) {
187 i_year_day = 1;
188 i_year++;
189 }
190 }
191 }
192 }
193
194 _date.set((int)i_year, (int)i_year_day);
195 _time.set((int)i_hr_day, (int)i_min_day, (double)i_sec_day);
196
197 assert(OK());
198}
199
200
201
202void
203DODS_Date_Time::set(string date_time)
204{
205 // Check for a fractional-date string and parse it if needed.
206 if (date_time.find(".") != string::npos) {
207 parse_fractional_time(date_time);
208 }
209 else {
210 // The format for the date-time string is <date part>:<time part>.
211 size_t i = date_time.find(":");
212 string date_part = date_time.substr(0, i);
213 string time_part = date_time.substr(i+1, date_time.size());
214
215 _date.set(date_part);
216 _time.set(time_part);
217 }
218
219 assert(OK());
220}
221
222void
223DODS_Date_Time::set(BaseType *date_time)
224{
225 set(extract_argument(date_time));
226}
227
228void
229DODS_Date_Time::set(int y, int m, int d, int hh, int mm, double ss, bool gmt)
230{
231 _date.set(y, m, d);
232 _time.set(hh, mm, ss, gmt);
233
234 assert(OK());
235}
236
237void
238DODS_Date_Time::set(int y, int yd, int hh, int mm, double ss, bool gmt)
239{
240 _date.set(y, yd);
241 _time.set(hh, mm, ss, gmt);
242
243 assert(OK());
244}
245
246int
248{
249 return _date.year();
250}
251
252int
254{
255 return _date.month();
256}
257
258int
260{
261 return _date.day();
262}
263
264int
266{
267 return _date.day_number();
268}
269
270int
272{
273 return _time.hours();
274}
275
276int
278{
279 return _time.minutes();
280}
281
282double
284{
285 return _time.seconds();
286}
287
288bool
290{
291 return _time.gmt();
292}
293
294string
295DODS_Date_Time::get(date_format format, bool gmt) const
296{
297 switch (format) {
298 case ymd:
299 return _date.get() + ":" + _time.get(gmt);
300 case yd:
301 return _date.get(yd) + ":" + _time.get(gmt);
302 case decimal: {
303 ostringstream oss;
304 oss.precision(14);
305
306 double decday = (_date.fraction()
307 + _time.fraction()/days_in_year(_date.year()));
308
309 oss << decday;
310
311 return oss.str();
312 }
313 default:
314#ifndef TEST
315 throw Error(unknown_error, "Invalid date format");
316#else
317 assert("Invalid date format" && false);
318#endif
319 }
320}
321
322double
324{
325 return _date.julian_day() + _time.seconds_since_midnight()/seconds_per_day;
326}
327
328time_t
330{
331 struct tm tm_rec{};
332 tm_rec.tm_mday = _date.day();
333 tm_rec.tm_mon = _date.month() - 1; // zero-based
334 tm_rec.tm_year = _date.year() - 1900; // years since 1900
335 tm_rec.tm_hour = _time.hours();
336 tm_rec.tm_min = _time.minutes();
337 tm_rec.tm_sec = (int)_time.seconds();
338 tm_rec.tm_isdst = -1;
339
340 return mktime(&tm_rec);
341}
342
343double
345{
346 return _time.get_epsilon();
347}
348
349void
351{
352 _time.set_epsilon(eps);
353}
354
355int
357{
358 return t1._date == t2._date && t1._time == t2._time;
359}
360
361int
363{
364 return t1._date != t2._date || t1._time != t2._time;
365}
366
367int
369{
370 return t1._date < t2._date
371 || (t1._date == t2._date && t1._time < t2._time);
372}
373
374int
376{
377 return t1._date > t2._date
378 || (t1._date == t2._date && t1._time > t2._time);
379}
380
381int
383{
384 return t1 == t2 || t1 < t2;
385}
386
387int
389{
390 return t1 == t2 || t1 > t2;
391}
392
393#ifdef DATE_TIME_TEST
394
395/* Input args: 1 string,
396 2 Two strings,
397 5 y, yd, hh, mm, ss,
398 6 y, m, d, hh, mm, ss
399
400 Compile using: g++ -g -I../../include -DHAVE_CONFIG_H -DTEST
401 -DDATE_TIME_TEST DODS_Date.cc DODS_Time.cc DODS_Date_Time.cc date_proc.cc
402 -lg++
403*/
404
405int
406main(int argc, char *argv[])
407{
409 DODS_Date_Time dt2("1970/1/1:0:0:0");
410
411 argc--;
412 switch(argc) {
413 case 1:
414 dt.set_date_time(argv[1]);
415 break;
416 case 2:
417 dt.set_date_time(argv[1]);
418 dt2.set_date_time(argv[2]);
419 break;
420 case 5:
421 dt.set_date_time(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]),
422 atoi(argv[4]), atof(argv[5]));
423 break;
424 case 6:
425 dt.set_date_time(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]),
426 atoi(argv[4]), atoi(argv[5]), atof(argv[6]));
427 break;
428 default:
429 cerr << "Wrong number of arguments!" << endl;
430 exit(1);
431 }
432
433 if (dt < dt2)
434 cout << "True: dt < dt2" << endl;
435 else
436 cout << "False: dt < dt2" << endl;
437
438 if (dt > dt2)
439 cout << "True: dt > dt2" << endl;
440 else
441 cout << "False: dt > dt2" << endl;
442
443 if (dt <= dt2)
444 cout << "True: dt <= dt2" << endl;
445 else
446 cout << "False: dt <= dt2" << endl;
447
448 if (dt >= dt2)
449 cout << "True: dt >= dt2" << endl;
450 else
451 cout << "False: dt >= dt2" << endl;
452
453 if (dt == dt2)
454 cout << "True: dt == dt2" << endl;
455 else
456 cout << "False: dt == dt2" << endl;
457
458 if (dt != dt2)
459 cout << "True: dt != dt2" << endl;
460 else
461 cout << "False: dt != dt2" << endl;
462
463 cout << "YMD: " << dt.ymd_date_time() << endl;
464 cout << "YD: " << dt.yd_date_time() << endl;
465 cout << "Julian day: " << dt.julian_day() << endl;
466 cout << "Seconds: " << dt.unix_time() << endl;
467}
468#endif // TEST_DATE
469
470// $Log: DODS_Date_Time.cc,v $
471// Revision 1.10 2004/02/04 20:50:08 jimg
472// Build fixes. No longer uses Pix.
473//
474// Revision 1.9 2003/12/08 21:59:52 edavis
475// Merge release-3-4 into trunk
476//
477// Revision 1.7.4.1 2003/06/29 05:37:32 rmorris
478// Include standard template libraries appropriately and add missing usage
479// statements.
480//
481// Revision 1.8 2003/05/14 19:23:13 jimg
482// Changed from strstream to sstream.
483//
484// Revision 1.7 2003/02/10 23:01:52 jimg
485// Merged with 3.2.5
486//
487// Revision 1.6.2.2 2002/12/18 23:30:42 pwest
488// gcc3.2 compile corrections, mainly regarding the using statement
489//
490// Revision 1.6.2.1 2002/11/13 05:58:05 dan
491// Fixed return variable name in get method, changed
492// from 'yd' to 'dateString'. 'yd' is also a value in
493// the enumeration type date_format.
494//
495// Revision 1.6 2000/10/11 19:37:55 jimg
496// Moved the CVS log entries to the end of files.
497// Changed the definition of the read method to match the dap library.
498// Added exception handling.
499// Added exceptions to the read methods.
500//
501// Revision 1.5 2000/08/31 22:16:53 jimg
502// Merged with 3.1.7
503//
504// Revision 1.4.2.1 2000/08/03 20:18:57 jimg
505// Removed config_dap.h and replaced it with config_ff.h (in *.cc files;
506// neither should be included in a header file).
507// Changed code that calculated leap year information so that it uses the
508// functions in date_proc.c/h.
509//
510// Revision 1.4 1999/07/22 21:28:09 jimg
511// Merged changes from the release-3-0-2 branch
512//
513// Revision 1.3.6.1 1999/06/01 15:38:06 jimg
514// Added code to parse and return floating point dates.
515//
516// Revision 1.3 1999/05/04 02:55:35 jimg
517// Merge with no-gnu
518//
519// Revision 1.2.8.1 1999/05/01 04:40:28 brent
520// converted old String.h to the new std C++ <string> code
521//
522// Revision 1.2 1999/01/05 00:35:35 jimg
523// Removed string class; replaced with the GNU string class. It seems those
524// don't mix well.
525// Switched to simpler method names.
526//
527// Revision 1.1 1998/12/30 06:40:39 jimg
528// Initial version
529//
bool OK() const
double julian_day() const
int minutes() const
friend int operator>=(DODS_Date_Time &t1, DODS_Date_Time &t2)
Greater-than or Equal-to.
string get(date_format format=ymd, bool gmt=true) const
friend int operator==(DODS_Date_Time &t1, DODS_Date_Time &t2)
Equality.
double get_epsilon() const
int day_number() const
void set_epsilon(double eps)
double seconds() const
void set(DODS_Date d, DODS_Time t)
friend int operator<(DODS_Date_Time &t1, DODS_Date_Time &t2)
Less-than.
int hours() const
int month() const
friend int operator!=(DODS_Date_Time &t1, DODS_Date_Time &t2)
Inequality.
time_t unix_time() const
friend int operator<=(DODS_Date_Time &t1, DODS_Date_Time &t2)
Less-than or Equal-to.
bool gmt() const
friend int operator>(DODS_Date_Time &t1, DODS_Date_Time &t2)
Greater-than.