Update copyright to LGPL on all files
[dyninst.git] / common / src / Time.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 #include <iostream>
33 #include <time.h>
34 #include <string.h>
35 #include <iomanip>
36 #include <stdio.h>
37 #include <assert.h>
38 #include <limits.h>
39 #include "common/h/Time.h"
40 #include "common/h/int64iostream.h"
41
42
43 timeUnit::ostream_fmt timeUnit::curFmt = timeUnit::sparse;
44
45 const timeUnit *timeUnit::_ns = NULL;
46 const timeUnit *timeUnit::_us = NULL;
47 const timeUnit *timeUnit::_ms = NULL;
48 const timeUnit *timeUnit::_sec = NULL;
49 const timeUnit *timeUnit::_minute = NULL;
50 const timeUnit *timeUnit::_hour = NULL;
51 const timeUnit *timeUnit::_day = NULL;
52 const timeUnit *timeUnit::_year = NULL;
53 const timeUnit *timeUnit::_leapYear = NULL;
54
55 // these helper functions will help reduce code bloat
56 // The ...Help functions are not inlined (or not included with their inlined
57 // user functions) because the Help functions call constructors which are
58 // also inlined and the result is the possibility for a lot of code bloat.
59 // So the reference is inlined, but the creation step (which only will happen
60 // once) is not inlined.
61
62 const timeUnit *timeUnit::nsHelp() {
63   return new timeUnit(fraction(1));
64 }
65 const timeUnit *timeUnit::usHelp() {
66   return new timeUnit(fraction(1000));
67 }
68 const timeUnit *timeUnit::msHelp() {
69   return new timeUnit(fraction(1000000));
70 }
71 const timeUnit *timeUnit::secHelp() {
72   return new timeUnit(fraction(1000000000));
73 }
74 const timeUnit *timeUnit::minHelp() {
75   int64_t ns_per_sec = sec().get_ns_per_unit().getNumer();
76   return new timeUnit(fraction(I64_C(60) * ns_per_sec));
77 }
78 const timeUnit *timeUnit::hourHelp() {
79   int64_t ns_per_min = minute().get_ns_per_unit().getNumer();
80   return new timeUnit(fraction(I64_C(60) * ns_per_min));
81 }
82 const timeUnit *timeUnit::dayHelp() {
83   int64_t ns_per_hour = hour().get_ns_per_unit().getNumer();
84   return new timeUnit(fraction(I64_C(24) * ns_per_hour));
85 }
86 const timeUnit *timeUnit::yearHelp() {
87   double ns_per_day =static_cast<double>(day().get_ns_per_unit().getNumer());
88   fraction ratio(static_cast<int64_t>(365 * ns_per_day));
89   return new timeUnit(ratio);
90 }
91 const timeUnit *timeUnit::leapYearHelp() {
92   double ns_per_day =static_cast<double>(day().get_ns_per_unit().getNumer());
93   fraction ratio(static_cast<int64_t>(366 * ns_per_day));
94   return new timeUnit(ratio);
95 }
96
97 const timeBase *timeBase::_bStd = NULL;
98 const timeBase *timeBase::_b1970 = NULL;
99
100 const timeBase *timeBase::bStdHelp() {
101   return new timeBase(0);
102 }
103 // if StdBase is changed, might need to change calculation of numLeapYears
104 const timeBase *timeBase::b1970Help() {
105   int64_t nsPerYear = timeUnit::year().get_ns_per_unit().getNumer();
106   int64_t nsPerLeapYear = timeUnit::leapYear().get_ns_per_unit().getNumer();
107   int numLeapYears = (StdBaseMark - 1970)/4;
108   int numStdYears  = (StdBaseMark - 1970) - numLeapYears;
109   return new timeBase(numStdYears * nsPerYear + 
110                       numLeapYears * nsPerLeapYear);
111 }
112
113
114 int64_t timeUnit::cvtTo_ns(double units) const {
115   double tns = ns_per_unit * units;
116   return static_cast<int64_t>(tns);
117 }
118
119 int64_t timeUnit::cvtTo_ns(int64_t units) const {
120   int64_t nsec;
121   nsec = ns_per_unit.multReturnInt64(units);
122   return nsec;
123 }
124
125 double timeUnit::cvtFrom_nsD(int64_t nsec) const {
126   return units_per_ns * (double)nsec;
127 }
128
129 int64_t timeUnit::cvtFrom_nsI(int64_t nsec) const {
130   int64_t units;
131   units = units_per_ns.multReturnInt64(nsec);
132   return units;
133 }
134
135 int64_t timeParent::getRolloverTime(double dt) {
136   // a modulus with doubles
137   int num = (int) (dt / (double)I64_MAX);
138   double rolloverAmt = dt - ((double) num * (double)I64_MAX);
139   return (int64_t) rolloverAmt;
140 }
141
142 const timeStamp *timeStamp::_ts1800  = NULL;
143 const timeStamp *timeStamp::_ts1970  = NULL;
144 const timeStamp *timeStamp::_tsStd   = NULL;
145 const timeStamp *timeStamp::_ts2200  = NULL;
146 // This 88 quintillion number is some 280 years.  For the timeLength class,
147 // this amount of time should be safely out of reach.  The timeStamp class is
148 // internally based at the year of timeBase::StdBaseMark, ie. year 2000, the
149 // uninitialized value represents a timeStamp around year 2280, plenty safe
150 // out of range for a long time.  We want the same number, eg. 8, for every
151 // digit of this number so it can be easily recognized from a debugger.
152 const int64_t    timeParent::uninitializedValue = I64_C(8888888888888888888);
153
154 const timeStamp *timeStamp::ts1800Help() {
155   timeStamp *p_ts1970 = new timeStamp(0, timeUnit::year(), timeBase::b1970());
156   *p_ts1970 -= 53*timeLength::year() + 17*timeLength::leapYear(); //1900 - 1970
157   // beginning 2000 (leap year) - beg 2100 (no leap year), 25 4 year spans
158   *p_ts1970 -= 76*timeLength::year() + 24*timeLength::leapYear();// 1800 - 1900
159   return p_ts1970;
160 }
161
162 const timeStamp *timeStamp::ts1970Help() {
163   return new timeStamp(0, timeUnit::sec(), timeBase::b1970());
164 }
165
166 const timeStamp *timeStamp::tsStdHelp() {
167   return new timeStamp(0, timeUnit::year(), timeBase::bStd());
168 }
169
170 const timeStamp *timeStamp::ts2200Help() {
171   timeStamp *p_ts1970 = new timeStamp(0, timeUnit::year(), timeBase::b1970());
172   *p_ts1970 += 23*timeLength::year() + 7*timeLength::leapYear(); // 1970 - 2000
173   // beginning 2000 (leap year) - beg 2100 (no leap year), 25 4 year spans
174   *p_ts1970 += 75*timeLength::year() + 25*timeLength::leapYear();
175   // beg 2100 (no leap year) - beg 2200 (no leap year), 25 4 year spans
176   *p_ts1970 += 76*timeLength::year() + 24*timeLength::leapYear();
177   return p_ts1970;
178 }
179
180 void timeStamp::initI(int64_t iTime, const timeUnit &u, timeBase b) {
181   assign( b.cvtTo_bStd( u.cvtTo_ns(iTime)));
182   /*  // if we allow exceptions in the future, we will be able to handle
183       // nicely cases of overflows in the fraction class
184       } catch(finalMultOverflowExc &) {
185       double dRes = static_cast<double>(b.cvtTo_bStd( u.cvtTo_ns(
186       static_cast<double>(iTime))));
187       assign( getRolloverTime(dRes));
188       }
189   */
190 }
191
192 void timeLength::initI(int64_t iTime, const timeUnit &u) {
193   assign( u.cvtTo_ns(iTime));
194   /*  // if we allow exceptions in the future, we will be able to handle
195       // nicely cases of overflows in the fraction class  
196       } catch(finalMultOverflowExc &) {
197       double dRes= static_cast<double>(u.cvtTo_ns(static_cast<double>(iTime)));
198       assign( getRolloverTime(dRes));
199       }
200   */
201 }
202
203 void relTimeStamp::initI(int64_t iTime, const timeUnit &u) {
204   assign( u.cvtTo_ns(iTime));
205   /*  // if we allow exceptions in the future, we will be able to handle
206       // nicely cases of overflows in the fraction class  
207       } catch(finalMultOverflowExc &) {
208       double dRes= static_cast<double>(u.cvtTo_ns(static_cast<double>(iTime)));
209       assign( getRolloverTime(dRes));
210       }
211   */
212 }
213
214 timeStamp::timeStamp(const timeLength &tl, timeBase b) : timeParent() {
215   initI(tl.getI(timeUnit::ns()), timeUnit::ns(), b);
216 }
217
218 timeStamp::timeStamp(double dTime, const timeUnit &u, timeBase b): timeParent()
219 {
220   double dRes = static_cast<double>(b.cvtTo_bStd( u.cvtTo_ns(dTime)));
221   if(dRes <= static_cast<double>(I64_MAX)) 
222     assign( static_cast<int64_t>(dRes));
223   else
224     assign( getRolloverTime(dRes));
225 }
226
227 const relTimeStamp *relTimeStamp::_Zero      = NULL;
228
229 const relTimeStamp *relTimeStamp::ZeroHelp() {
230   return new relTimeStamp(0, timeUnit::sec());
231 }
232
233 const timeLength *timeLength::_zero = NULL;
234 const timeLength *timeLength::ZeroHelp() {
235   return new timeLength(0, timeUnit::sec());
236 }
237
238 relTimeStamp::relTimeStamp(const timeLength &tl) : timeParent() {
239   initI(tl.getI(timeUnit::ns()), timeUnit::ns());
240 }
241
242 relTimeStamp::relTimeStamp(double dTime, const timeUnit &u): timeParent()
243 {
244   double dRes = static_cast<double>( u.cvtTo_ns(dTime));
245   if(dRes <= static_cast<double>(I64_MAX)) 
246     assign( static_cast<int64_t>(dRes));
247   else
248     assign( getRolloverTime(dRes));
249 }
250
251 const timeLength *timeLength::_ns = NULL;
252 const timeLength *timeLength::nsHelp() {
253   return new timeLength(1, timeUnit::ns());
254 }
255 const timeLength *timeLength::_us = NULL;
256 const timeLength *timeLength::usHelp() {
257   return new timeLength(1, timeUnit::us());
258 }
259 const timeLength *timeLength::_ms = NULL;
260 const timeLength *timeLength::msHelp() {
261   return new timeLength(1, timeUnit::ms());
262 }
263 const timeLength *timeLength::_sec = NULL;
264 const timeLength *timeLength::secHelp() {
265   return new timeLength(1, timeUnit::sec());
266 }
267 const timeLength *timeLength::_minute = NULL;
268 const timeLength *timeLength::minHelp() {
269   return new timeLength(1, timeUnit::minute());
270 }
271 const timeLength *timeLength::_hour = NULL;
272 const timeLength *timeLength::hourHelp() {
273   return new timeLength(1, timeUnit::hour());
274 }
275 const timeLength *timeLength::_day = NULL;
276 const timeLength *timeLength::dayHelp() {
277   return new timeLength(1, timeUnit::day());
278 }
279 const timeLength *timeLength::_year = NULL;
280 const timeLength *timeLength::yearHelp() {
281   return new timeLength(1, timeUnit::year());
282 }
283 const timeLength *timeLength::_leapYear = NULL;
284 const timeLength *timeLength::leapYearHelp() {
285   return new timeLength(1, timeUnit::leapYear());
286 }
287
288
289 timeLength::timeLength(double dTime, const timeUnit &u) : timeParent() {
290   double dRes = static_cast<double>(u.cvtTo_ns(dTime));
291   if(dRes <= static_cast<double>(I64_MAX)) 
292     assign( static_cast<int64_t>(dRes));
293   else
294     assign( getRolloverTime(dRes));
295 }
296
297 ostream& operator<<(ostream&s, const timeUnit::ostream_fmt &u) {
298   timeUnit::curFmt = u;
299   return s;
300 }
301
302 ostream& operator<<(ostream&s, const timeUnit &u) {
303   if(timeUnit::curFmt == timeUnit::sparse) {
304     s << "["<< fraction::sparse << u.get_ns_per_unit()<<"]";
305   } else { // timeUnit::verbose
306     s << fraction::verbose << "[ns_per_unit: " << u.get_ns_per_unit() 
307       << ", units_per_ns: " << u.get_units_per_ns() << "]";
308   }
309   return s;
310 }
311
312 ostream& operator<<(ostream&s, timeBase b) {
313   s << timeStamp(-b.get_ns2StdBaseMark(),timeUnit::ns(),timeBase::bStd());
314   return s;
315 }
316
317 /*
318 ostream& operator<<(ostream& s, const timeParent &tp) {
319   return tp.put(s);
320 }
321 */
322
323 // only handles positives right now
324 // string buffer should be atleast 16
325 void insCommas(int num, char strbuf[]) {
326     char nsStr[20];
327     sprintf(nsStr,"%12d",num);
328     int nextIdx=0;
329     if(num>=1000000000) {
330       strncpy(&strbuf[nextIdx], &nsStr[0], 3);
331       nextIdx+=3;
332       strbuf[nextIdx++] = ',';  
333     }
334     if(num>=1000000) {
335       strncpy(&strbuf[nextIdx], &nsStr[3], 3);
336       nextIdx+=3;
337       strbuf[nextIdx++] = ',';  
338     }
339     if(num>=1000) {
340       strncpy(&strbuf[nextIdx], &nsStr[6], 3);
341       nextIdx+=3;
342       strbuf[nextIdx++] = ',';  
343     }
344     if(num>=0) {
345       strncpy(&strbuf[nextIdx], &nsStr[9], 3);
346       nextIdx+=3;
347     }
348     strbuf[nextIdx]=0;
349 }
350
351 ostream& operator<<(ostream&s, timeLength z) {
352   timeLength tUser = z;
353   int years = static_cast<int>(tUser.getI(timeUnit::year()));
354   timeLength tempT(years,timeUnit::year());
355   tUser -= tempT;
356   int days  = static_cast<int>(tUser.getI(timeUnit::day()));
357   tUser -= timeLength(days,timeUnit::day());
358   int hours = static_cast<int>(tUser.getI(timeUnit::hour()));
359   tUser -= timeLength(hours,timeUnit::hour());
360   int mins  = static_cast<int>(tUser.getI(timeUnit::minute()));
361   tUser -= timeLength(mins,timeUnit::minute());
362   int secs  = static_cast<int>(tUser.getI(timeUnit::sec()));
363   tUser -= timeLength(secs,timeUnit::sec());
364   int ms    = static_cast<int>(tUser.getI(timeUnit::ms()));
365   tUser -= timeLength(ms,timeUnit::ms());
366   int us    = static_cast<int>(tUser.getI(timeUnit::us()));
367   tUser -= timeLength(us,timeUnit::us());
368   int ns    = static_cast<int>(tUser.getI(timeUnit::ns()));
369
370   bool prev = false, compact = false;
371   char cSt[5] = ", ";
372   // this is a hack for those that want to print the time compressed
373   if(s.flags() & ostream::oct) {  compact=true;  s.flags(ostream::dec);  }
374   if(compact == true) strcpy(cSt,",");
375   s << "[";
376   if(z.get_ns() == 0) {  s << "0 time"; }
377   else {
378     if(years!=0) {  s << (prev? cSt:"") << years << " years";   prev=true; }
379     if(days!=0)  {  s << (prev? cSt:"") << days  << " days";    prev=true; }
380     if(hours!=0) {  s << (prev? cSt:"") << hours << " hours";   prev=true; }
381     if(mins!=0)  {  s << (prev? cSt:"") << mins  << " mins";    prev=true; }
382     if(secs!=0)  {  s << (prev? cSt:"") << secs  << " secs";    prev=true; }
383     if(ms!=0)    {  s << (prev? cSt:"") << ms    << " ms";      prev=true; }
384     if(us!=0)    {  s << (prev? cSt:"") << us    << " us";      prev=true; }
385     if(ns!=0)    {  s << (prev? cSt:"") << ns    << " ns";      prev=true; }
386   }
387   s << "]";
388   return s;
389 }
390
391 ostream& operator<<(ostream&s, timeStamp z) {
392   time_t s1970 = static_cast<time_t>(z.getI(timeUnit::sec(), timeBase::b1970()));
393   int64_t nsI1970 = static_cast<int64_t>(s1970) * I64_C(1000000000);
394   if(! z.isInitialized()) {  
395     s << "[uninitialized]";
396   } else if(z < timeStamp(0, timeUnit::year(), timeBase::b1970())) {
397     timeLength tl(z - timeStamp(0, timeUnit::year(), timeBase::b1970()));
398     // setting the oct flag is just a hack to tell the timeLength ostream<<
399     // to print the time compressed
400 #if !defined(os_windows)
401     ostream::fmtflags oldflags;
402 #else
403     long oldflags;  // irix,nt environment doesn't define ostream::fmtflags
404 #endif
405     oldflags = s.flags(ostream::oct);
406     s << "[1970 + " << tl << "]"; 
407     s.flags(oldflags);
408   } else {
409     int64_t nstot = z.getI(timeUnit::ns(), timeBase::b1970());
410     int64_t nsrem = nstot - nsI1970;
411     char dateStr[50];
412     s1970 = mktime(localtime(&s1970));
413     strcpy(dateStr, ctime(&s1970));
414     char *p = strstr(dateStr, "\n");  // erase the nl
415     if(p != NULL) {  *p++ = 0;   *p = 0; }
416     char strFmt[30];
417     insCommas(static_cast<int>(nsrem), strFmt);
418     s << "[" << dateStr << "  " << strFmt << "ns]";
419   }
420   return s;
421 }
422
423 ostream& operator<<(ostream&s, relTimeStamp z) {
424   if(! z.isInitialized()) {  
425     s << "[uninitialized]";
426   } else {
427     timeLength t(z.getI(timeUnit::ns()), timeUnit::ns());
428     s << t;
429   }
430   return s;
431 }
432
433 // timeLength / timeLength = double
434 double operator/(const timeLength a, const timeLength b) {
435   assert(a.isInitialized() && b.isInitialized());
436   return static_cast<double>(a.get_ns()) / static_cast<double>(b.get_ns());
437 }
438
439 bool timeParent::isInitialized() const {  
440   if(get_ns() == uninitializedValue) return false;
441   else return true;
442 }
443
444 timeParent::timeParent() 
445   : ns(uninitializedValue) 
446
447 }
448
449 timeParent::timeParent(int64_t _ns) 
450   : ns(_ns) 
451
452 }
453
454 COMMON_EXPORT timeStamp::timeStamp(int64_t iTime, const timeUnit &u, timeBase b) 
455   : timeParent()
456 {
457   initI(iTime, u, b);
458 }
459
460 COMMON_EXPORT timeStamp::timeStamp(int iTime, const timeUnit &u, timeBase b) 
461   : timeParent() 
462 {
463   initI(iTime, u, b);
464 }
465
466 COMMON_EXPORT relTimeStamp::relTimeStamp(int64_t iTime, const timeUnit &u) : timeParent() {
467   initI(iTime, u);
468 }
469
470 COMMON_EXPORT relTimeStamp::relTimeStamp(int iTime, const timeUnit &u) : timeParent() {
471   initI(iTime, u);
472 }
473
474 COMMON_EXPORT timeLength::timeLength(int64_t iTime, const timeUnit &u)
475   : timeParent() 
476 {
477   initI(iTime, u);
478 }
479
480 COMMON_EXPORT timeLength::timeLength(int iTime, const timeUnit &u)  
481   : timeParent() 
482 {
483   initI(static_cast<int64_t>(iTime), u);
484 }
485
486 COMMON_EXPORT timeStamp::timeStamp(int64_t ns_)
487   : timeParent(ns_)
488 {
489 }
490
491 const timeLength &timeLength::Zero() {
492   if(_zero == NULL) _zero = ZeroHelp();
493   return *_zero;
494 }
495 const timeLength &timeLength::ns() {
496   if(_ns == NULL) _ns = nsHelp();
497   return *_ns;
498 }
499 const timeLength &timeLength::us() {
500   if(_us == NULL) _us = usHelp();
501   return *_us;
502 }
503 const timeLength &timeLength::ms() {
504   if(_ms == NULL) _ms = msHelp();
505   return *_ms;
506 }
507 const timeLength &timeLength::sec() {
508   if(_sec == NULL) _sec = secHelp();
509   return *_sec;
510 }
511 const timeLength &timeLength::minute() {
512   if(_minute == NULL) _minute = minHelp();
513   return *_minute;
514 }
515 const timeLength &timeLength::hour() {
516   if(_hour == NULL) _hour = hourHelp();
517   return *_hour;
518 }
519 const timeLength &timeLength::day() {
520   if(_day == NULL) _day = dayHelp();
521   return *_day;
522 }
523 const timeLength &timeLength::year() {
524   if(_year == NULL) _year = yearHelp();
525   return *_year;
526 }
527 const timeLength &timeLength::leapYear() {
528   if(_leapYear == NULL) _leapYear = leapYearHelp();
529   return *_leapYear;
530 }
531
532 // timeStamp +=/-= timeLength
533 const timeStamp operator+=(timeStamp &ts, timeLength tl) {
534   assert(ts.isInitialized() && tl.isInitialized());
535   ts.assign(ts.get_ns() + tl.get_ns());
536   return ts;
537 }
538 COMMON_EXPORT const timeStamp operator-=(timeStamp &ts, timeLength tl) {
539   assert(ts.isInitialized() && tl.isInitialized());
540   ts.assign(ts.get_ns() - tl.get_ns());
541   return ts;
542 }
543
544 // timeLength +=/-= timeLength
545 const timeLength operator+=(timeLength &t, timeLength tl) {
546   assert(t.isInitialized() && tl.isInitialized());
547   t.assign(t.get_ns() + tl.get_ns());
548   return t;
549 }
550 const timeLength operator-=(timeLength &t, timeLength tl) {
551   assert(t.isInitialized() && tl.isInitialized());
552   t.assign(t.get_ns() - tl.get_ns());
553   return t;
554 }
555
556 // timeLength *=, /= double
557 const timeLength operator*=(timeLength &t, double d) {
558   assert(t.isInitialized());
559   t.assign(static_cast<int64_t>(static_cast<double>(t.get_ns()) * d));
560   return t;
561 }
562 const timeLength operator/=(timeLength &t, double d) {
563   assert(t.isInitialized());
564   t.assign(static_cast<int64_t>(static_cast<double>(t.get_ns()) / d));
565   return t;
566 }
567
568 // - timeLength
569 const timeLength operator-(const timeLength &t) {
570   assert(t.isInitialized());
571   return timeLength(-t.get_ns());
572 }
573
574 // timeStamp - timeStamp = timeLength  ;  the length of time between time stamps
575 const timeLength operator-(const timeStamp a, const timeStamp b) {
576   assert(a.isInitialized() && b.isInitialized());
577   return timeLength(a.get_ns() - b.get_ns());
578 }
579
580 // timeStamp +/- timeLength = timeStamp
581 const timeStamp operator+(const timeStamp a, const timeLength b) {
582   assert(a.isInitialized() && b.isInitialized());
583   return timeStamp(a.get_ns() + b.get_ns());
584 }
585 const timeStamp operator-(const timeStamp a, const timeLength b) {
586   assert(a.isInitialized() && b.isInitialized());
587   return timeStamp(a.get_ns() - b.get_ns());
588 }
589
590 // timeLength + timeStamp = timeStamp
591 const timeStamp operator+(const timeLength a, const timeStamp b) {
592   assert(a.isInitialized() && b.isInitialized());
593   return timeStamp(a.get_ns() + b.get_ns());
594 }
595 // timeLength - timeStamp doesn't make sense, ie. 3 days - Mar 9 = ?
596
597 // timeLength +/- timeLength = timeLength
598 const timeLength operator+(const timeLength a, const timeLength b) {  
599   assert(a.isInitialized() && b.isInitialized());
600   return timeLength(a.get_ns() + b.get_ns());
601 }
602 const timeLength operator-(const timeLength a, const timeLength b) {
603   assert(a.isInitialized() && b.isInitialized());
604   return timeLength(a.get_ns() - b.get_ns());
605 }
606
607 // timeLength */ double = timeLength
608 const timeLength operator*(const timeLength a, const double b) {
609   assert(a.isInitialized());
610   return timeLength(static_cast<int64_t>(static_cast<double>(a.get_ns()) * b));
611 }
612 const timeLength operator/(const timeLength a, const double b) {
613   assert(a.isInitialized());
614   return timeLength(static_cast<int64_t>(static_cast<double>(a.get_ns()) / b));
615 }
616
617 // double */ timeLength = timeLength
618 const timeLength operator*(const double a, const timeLength b) {
619   assert(b.isInitialized());
620   return timeLength(static_cast<int64_t>(a * static_cast<double>(b.get_ns())));
621 }
622 const timeLength operator/(const double a, const timeLength b) {
623   assert(b.isInitialized());
624   return timeLength(static_cast<int64_t>(a / static_cast<double>(b.get_ns())));
625 }
626
627 // Be careful if writing * operators because Time is based at nanosecond
628 // level, which can overflow when multiplying times that seem small
629 // eg. Time(1,timeUnit::day) * Time(2,timeUnit::day) will overflow
630
631 // timeStamp @ timeStamp = bool
632 bool operator==(const timeStamp a, const timeStamp b) {
633   assert(a.isInitialized() && b.isInitialized());
634   return (a.get_ns() == b.get_ns());
635 }
636 bool operator!=(const timeStamp a, const timeStamp b) {
637   assert(a.isInitialized() && b.isInitialized());
638   return (a.get_ns() != b.get_ns());
639 }
640 bool operator>(const timeStamp a, const timeStamp b) {
641   assert(a.isInitialized() && b.isInitialized());
642   return (a.get_ns() > b.get_ns());
643 }
644 bool operator>=(const timeStamp a, const timeStamp b) {
645   assert(a.isInitialized() && b.isInitialized());
646   return (a.get_ns() >= b.get_ns());
647 }
648 bool operator<(const timeStamp a, const timeStamp b) {
649   assert(a.isInitialized() && b.isInitialized());
650   return (a.get_ns() < b.get_ns());
651 }
652 bool operator<=(const timeStamp a, const timeStamp b) {
653   assert(a.isInitialized() && b.isInitialized());
654   return (a.get_ns() <= b.get_ns());
655 }
656
657 timeStamp earlier(const timeStamp a, const timeStamp b) {
658   assert(a.isInitialized() && b.isInitialized());
659   if(a <= b)  return a;
660   else        return b;
661 }
662
663 timeStamp later(const timeStamp a, const timeStamp b) {
664   assert(a.isInitialized() && b.isInitialized());
665   if(a >= b)  return a;
666   else        return b;
667 }
668
669 // timeLength @ timeLength = bool
670 bool operator==(const timeLength a, const timeLength b) {
671   assert(a.isInitialized() && b.isInitialized());
672   return (a.get_ns() == b.get_ns());
673 }
674 bool operator!=(const timeLength a, const timeLength b) {
675   assert(a.isInitialized() && b.isInitialized());
676   return (a.get_ns() != b.get_ns());
677 }
678 bool operator>(const timeLength a, const timeLength b) {
679   assert(a.isInitialized() && b.isInitialized());
680   return (a.get_ns() > b.get_ns());
681 }
682 bool operator>=(const timeLength a, const timeLength b) {
683   assert(a.isInitialized() && b.isInitialized());
684   return (a.get_ns() >= b.get_ns());
685 }
686 bool operator<(const timeLength a, const timeLength b) {
687   assert(a.isInitialized() && b.isInitialized());
688   return (a.get_ns() < b.get_ns());
689 }
690 bool operator<=(const timeLength a, const timeLength b) {
691   assert(a.isInitialized() && b.isInitialized());
692   return (a.get_ns() <= b.get_ns());
693 }
694
695
696 timeLength minimum(const timeLength a, const timeLength b) {  
697   assert(a.isInitialized() && b.isInitialized());
698   if(a<=b)  return a;
699   else      return b;
700 }
701
702 timeLength maximum(const timeLength a, const timeLength b) {  
703   assert(a.isInitialized() && b.isInitialized());
704   if(a>=b)  return a;
705   else      return b;
706 }
707
708 const timeLength abs(const timeLength a) {  
709   assert(a.isInitialized());
710   return maximum(a,-a);
711 }
712
713 // need to put this here so can get at timeStamp
714 timeBase::timeBase(timeStamp mark) {
715   ns2StdBaseMark = -mark.get_ns();  // in Std base
716   // eg. (2001) 1 year of ns's -> -1 year of ns's to internalTimeBaseMark
717 }
718
719 // relTimeStamp +=/-= timeLength
720 const relTimeStamp operator+=(relTimeStamp &ts, timeLength tl) {
721   assert(ts.isInitialized() && tl.isInitialized());
722   ts.assign(ts.get_ns() + tl.get_ns());
723   return ts;
724 }
725 const relTimeStamp operator-=(relTimeStamp &ts, timeLength tl) {
726   assert(ts.isInitialized() && tl.isInitialized());
727   ts.assign(ts.get_ns() - tl.get_ns());
728   return ts;
729 }
730
731 // relTimeStamp - relTimeStamp = timeLength  ;  the length of time between time stamps
732 const timeLength operator-(const relTimeStamp a, const relTimeStamp b) {
733   assert(a.isInitialized() && b.isInitialized());
734   return timeLength(a.get_ns() - b.get_ns());
735 }
736
737 // relTimeStamp +/- relTimeLength = relTimeStamp
738 const relTimeStamp operator+(const relTimeStamp a, const timeLength b) {
739   assert(a.isInitialized() && b.isInitialized());
740   return relTimeStamp(a.get_ns() + b.get_ns());
741 }
742 const relTimeStamp operator-(const relTimeStamp a, const timeLength b) {
743   assert(a.isInitialized() && b.isInitialized());
744   return relTimeStamp(a.get_ns() - b.get_ns());
745 }
746
747 // timeLength + relTimeStamp = relTimeStamp
748 const relTimeStamp operator+(const timeLength a, const relTimeStamp b) {
749   assert(a.isInitialized() && b.isInitialized());
750   return relTimeStamp(a.get_ns() + b.get_ns());
751 }
752 // timeLength - timeStamp doesn't make sense, ie. 3 days - Mar 9 = ?
753
754
755 // Be careful if writing * operators because Time is based at nanosecond
756 // level, which can overflow when multiplying times that seem small
757 // eg. Time(1,timeUnit::day) * Time(2,timeUnit::day) will overflow
758
759 // relTimeStamp @ relTimeStamp = bool
760 bool operator==(const relTimeStamp a, const relTimeStamp b) {
761   assert(a.isInitialized() && b.isInitialized());
762   return (a.get_ns() == b.get_ns());
763 }
764 bool operator!=(const relTimeStamp a, const relTimeStamp b) {
765   assert(a.isInitialized() && b.isInitialized());
766   return (a.get_ns() != b.get_ns());
767 }
768 bool operator>(const relTimeStamp a, const relTimeStamp b) {
769   assert(a.isInitialized() && b.isInitialized());
770   return (a.get_ns() > b.get_ns());
771 }
772 bool operator>=(const relTimeStamp a, const relTimeStamp b) {
773   assert(a.isInitialized() && b.isInitialized());
774   return (a.get_ns() >= b.get_ns());
775 }
776 bool operator<(const relTimeStamp a, const relTimeStamp b) {
777   assert(a.isInitialized() && b.isInitialized());
778   return (a.get_ns() < b.get_ns());
779 }
780 bool operator<=(const relTimeStamp a, const relTimeStamp b) {
781   assert(a.isInitialized() && b.isInitialized());
782   return (a.get_ns() <= b.get_ns());
783 }
784
785 relTimeStamp earlier(const relTimeStamp a, const relTimeStamp b) {
786   assert(a.isInitialized() && b.isInitialized());
787   if(a <= b)  return a;
788   else        return b;
789 }
790
791 relTimeStamp later(const relTimeStamp a, const relTimeStamp b) {
792   assert(a.isInitialized() && b.isInitialized());
793   if(a >= b)  return a;
794   else        return b;
795 }
796
797 timeUnit::timeUnit(fraction _ns_per_unit) : ns_per_unit(_ns_per_unit), 
798   units_per_ns(ns_per_unit.reciprocal()) {
799   ns_per_unit.reduce();
800   units_per_ns.reduce();
801 }
802
803 // Selectors
804 fraction timeUnit::get_ns_per_unit()  const {  return ns_per_unit;   }
805 fraction timeUnit::get_units_per_ns() const {  return units_per_ns;  }
806
807 // Mutators
808 void timeUnit::set_ns_per_unit(const fraction &nspu) {
809   ns_per_unit = nspu;
810   units_per_ns = ns_per_unit.reciprocal();
811 }
812
813 const timeUnit &timeUnit::ns() {
814   if(_ns == NULL)  _ns = nsHelp();
815   return *_ns;
816 }
817 const timeUnit &timeUnit::us() {
818   if(_us == NULL)  _us = usHelp();
819   return *_us;
820 }
821 const timeUnit &timeUnit::ms() {
822   if(_ms==NULL)  _ms = msHelp();
823   return *_ms;
824 }
825 const timeUnit &timeUnit::sec() {
826   if(_sec==NULL) _sec = secHelp();
827   return *_sec;
828 }
829 const timeUnit &timeUnit::minute() {
830   if(_minute==NULL)  _minute = minHelp();
831   return *_minute;
832 }
833 const timeUnit &timeUnit::hour() {
834   if(_hour==NULL) _hour = hourHelp();
835   return *_hour;
836 }
837 const timeUnit &timeUnit::day() {
838   if(_day==NULL) _day = dayHelp();
839   return *_day;
840 }
841 const timeUnit &timeUnit::year() {
842   if(_year==NULL) _year = yearHelp();
843   return *_year;
844 }
845 const timeUnit &timeUnit::leapYear() {
846   if(_leapYear==NULL) _leapYear = leapYearHelp();
847   return *_leapYear;
848 }
849
850
851 timeBase::timeBase(int64_t ns2stdMark) {
852   ns2StdBaseMark = ns2stdMark;
853 }
854
855 int64_t timeBase::get_ns2StdBaseMark() const {
856   return ns2StdBaseMark;
857 }
858
859 int64_t timeBase::cvtTo_bStd(int64_t ns) const {
860   // eg. 1994, b1970 -> bStd:  24 yrs - 30 yrs = -6 yrs
861   return ns - ns2StdBaseMark;  
862 }
863
864 double  timeBase::cvtFrom_bStd(double ns) const {
865   // eg. 1994, bStd -> b1970:  -6 yrs + 30 yrs = 24 yrs
866    return ns + static_cast<double>(ns2StdBaseMark);
867 }
868
869 int64_t timeBase::cvtFrom_bStd(int64_t ns) const {
870   return ns + ns2StdBaseMark;
871 }
872
873 const timeBase &timeBase::bStd() {
874   if(_bStd == NULL) _bStd = bStdHelp();
875   return *_bStd;
876 }
877 const timeBase &timeBase::b1970() {
878   if(_b1970 == NULL) _b1970 = b1970Help();
879   return *_b1970;
880 }
881 const timeBase &timeBase::bNone() {
882   return bStd();
883 }
884
885
886 int64_t timeParent::get_ns() const {
887   return ns;
888 }
889
890 void timeParent::assign(const int64_t v) 
891 {  
892   ns = v;  
893 }
894
895 timeStamp::timeStamp() { }
896
897 double timeStamp::getD(const timeUnit &u, timeBase b) const {
898   return u.cvtFrom_nsD( b.cvtFrom_bStd(get_ns()));
899 }
900
901 int64_t timeStamp::getI(const timeUnit &u, timeBase b) const {
902   return u.cvtFrom_nsI( b.cvtFrom_bStd(get_ns()));
903 }
904
905 const timeStamp &timeStamp::ts1970() {
906   if(_ts1970 == NULL)  _ts1970 = ts1970Help();
907   return *_ts1970;
908 }
909
910 const timeStamp &timeStamp::tsStd() {
911   if(_tsStd == NULL)  _tsStd = tsStdHelp();
912   return *_tsStd;
913 }
914
915 const timeStamp &timeStamp::ts1800() {
916   if(_ts1800 == NULL)  _ts1800 = ts1800Help();
917   return *_ts1800;
918 }
919
920 const timeStamp &timeStamp::ts2200() {
921   if(_ts2200 == NULL)  _ts2200 = ts2200Help();
922   return *_ts2200;
923 }
924
925 const timeStamp &timeStamp::tsLongAgoTime() {
926   return timeStamp::ts1800();
927 }
928
929 const timeStamp &timeStamp::tsFarOffTime() {
930   return timeStamp::ts2200();
931 }
932
933 COMMON_EXPORT relTimeStamp::relTimeStamp() { }
934
935 double relTimeStamp::getD(const timeUnit &u) const {
936   return u.cvtFrom_nsD(get_ns());
937 }
938
939 int64_t relTimeStamp::getI(const timeUnit &u) const {
940   return u.cvtFrom_nsI( get_ns());
941 }
942
943 relTimeStamp::relTimeStamp(int64_t ns_) : timeParent(ns_) { }
944
945 const relTimeStamp &relTimeStamp::Zero() {
946   if(_Zero == NULL)  _Zero = ZeroHelp();
947   return *_Zero;
948 }
949
950 COMMON_EXPORT timeLength::timeLength() 
951 {
952 }
953
954 double timeLength::getD(const timeUnit &u) const 
955 {
956         return u.cvtFrom_nsD( get_ns());
957 }
958
959 int64_t timeLength::getI(const timeUnit &u) const 
960 {
961   return u.cvtFrom_nsI( get_ns());
962 }
963
964 timeLength::timeLength(int64_t ns_) : timeParent(ns_)
965 {
966 }