bes  Updated for version 3.20.6
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 
37 static 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 "Error.h"
48 #include "DODS_Date_Time.h"
49 #include "date_proc.h"
50 #include "debug.h"
51 
52 using namespace std;
53 
54 #define seconds_per_day 86400.0
55 
56 using namespace std;
57 
58 static string
59 extract_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 
83 bool
85 {
86  return _time.OK() && _date.OK();
87 }
88 
90 {
91 }
92 
93 
95 {
96 }
97 
99 {
100  set(date_time);
101 }
102 
103 DODS_Date_Time::DODS_Date_Time(BaseType *date_time)
104 {
105  set(date_time);
106 }
107 
108 DODS_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 
114 DODS_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 
120 void
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 
131 void
132 DODS_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 
202 void
203 DODS_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 
222 void
223 DODS_Date_Time::set(BaseType *date_time)
224 {
225  set(extract_argument(date_time));
226 }
227 
228 void
229 DODS_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 
237 void
238 DODS_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 
246 int
248 {
249  return _date.year();
250 }
251 
252 int
254 {
255  return _date.month();
256 }
257 
258 int
260 {
261  return _date.day();
262 }
263 
264 int
266 {
267  return _date.day_number();
268 }
269 
270 int
272 {
273  return _time.hours();
274 }
275 
276 int
278 {
279  return _time.minutes();
280 }
281 
282 double
284 {
285  return _time.seconds();
286 }
287 
288 bool
290 {
291  return _time.gmt();
292 }
293 
294 string
295 DODS_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 
322 double
324 {
325  return _date.julian_day() + _time.seconds_since_midnight()/seconds_per_day;
326 }
327 
328 time_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 
343 double
345 {
346  return _time.get_epsilon();
347 }
348 
349 void
351 {
352  _time.set_epsilon(eps);
353 }
354 
355 int
356 operator==(DODS_Date_Time &t1, DODS_Date_Time &t2)
357 {
358  return t1._date == t2._date && t1._time == t2._time;
359 }
360 
361 int
362 operator!=(DODS_Date_Time &t1, DODS_Date_Time &t2)
363 {
364  return t1._date != t2._date || t1._time != t2._time;
365 }
366 
367 int
368 operator<(DODS_Date_Time &t1, DODS_Date_Time &t2)
369 {
370  return t1._date < t2._date
371  || (t1._date == t2._date && t1._time < t2._time);
372 }
373 
374 int
375 operator>(DODS_Date_Time &t1, DODS_Date_Time &t2)
376 {
377  return t1._date > t2._date
378  || (t1._date == t2._date && t1._time > t2._time);
379 }
380 
381 int
382 operator<=(DODS_Date_Time &t1, DODS_Date_Time &t2)
383 {
384  return t1 == t2 || t1 < t2;
385 }
386 
387 int
388 operator>=(DODS_Date_Time &t1, DODS_Date_Time &t2)
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 
405 int
406 main(int argc, char *argv[])
407 {
408  DODS_Date_Time dt;
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 //
DODS_Time
Definition: DODS_Time.h:63
DODS_Date_Time::day_number
int day_number() const
Definition: DODS_Date_Time.cc:265
DODS_Date_Time::year
int year() const
Definition: DODS_Date_Time.cc:247
DODS_Date_Time::get_epsilon
double get_epsilon() const
Definition: DODS_Date_Time.cc:344
DODS_Date::julian_day
long julian_day() const
Definition: DODS_Date.cc:412
DODS_Date_Time::hours
int hours() const
Definition: DODS_Date_Time.cc:271
DODS_Date_Time::set_epsilon
void set_epsilon(double eps)
Definition: DODS_Date_Time.cc:350
DODS_Time::gmt
bool gmt() const
Definition: DODS_Time.cc:288
DODS_Date
Definition: DODS_Date.h:108
DODS_Date_Time::OK
bool OK() const
Definition: DODS_Date_Time.cc:84
DODS_Time::seconds_since_midnight
double seconds_since_midnight() const
Definition: DODS_Time.cc:264
DODS_Time::hours
int hours() const
Definition: DODS_Time.cc:270
DODS_Time::seconds
double seconds() const
Definition: DODS_Time.cc:282
DODS_Time::set
void set(string time)
Definition: DODS_Time.cc:140
DODS_Date::month
int month() const
Definition: DODS_Date.cc:397
DODS_Time::get_epsilon
double get_epsilon() const
Definition: DODS_Time.cc:211
DODS_Time::set_epsilon
void set_epsilon(double eps)
Definition: DODS_Time.cc:217
DODS_Time::minutes
int minutes() const
Definition: DODS_Time.cc:276
DODS_Date_Time::julian_day
double julian_day() const
Definition: DODS_Date_Time.cc:323
DODS_Date::day
int day() const
Definition: DODS_Date.cc:402
DODS_Date_Time::DODS_Date_Time
DODS_Date_Time()
Definition: DODS_Date_Time.cc:89
DODS_Date::day_number
int day_number() const
Definition: DODS_Date.cc:407
DODS_Date::year
int year() const
Definition: DODS_Date.cc:392
DODS_Date_Time::day
int day() const
Definition: DODS_Date_Time.cc:259
DODS_Date_Time::set
void set(DODS_Date d, DODS_Time t)
Definition: DODS_Date_Time.cc:121
DODS_Date_Time::gmt
bool gmt() const
Definition: DODS_Date_Time.cc:289
DODS_Date_Time::month
int month() const
Definition: DODS_Date_Time.cc:253
Error
DODS_Date::set
void set(string date)
Definition: DODS_Date.cc:290
DODS_Date_Time::seconds
double seconds() const
Definition: DODS_Date_Time.cc:283
DODS_Date_Time::unix_time
time_t unix_time() const
Definition: DODS_Date_Time.cc:329
DODS_Date::get
string get(date_format format=ymd) const
Definition: DODS_Date.cc:429
DODS_Date_Time::minutes
int minutes() const
Definition: DODS_Date_Time.cc:277
DODS_Date_Time::get
string get(date_format format=ymd, bool gmt=true) const
Definition: DODS_Date_Time.cc:295
DODS_Time::fraction
double fraction() const
Definition: DODS_Time.cc:94
DODS_Date_Time
Definition: DODS_Date_Time.h:47
DODS_Time::get
string get(bool gmt=true) const
Definition: DODS_Time.cc:294