1
2 /* Web Polygraph http://www.web-polygraph.org/
3 * Copyright 2003-2011 The Measurement Factory
4 * Licensed under the Apache License, Version 2.0 */
5
6 #include "xstd/xstd.h"
7
8 #include <limits.h>
9 #include <stdlib.h>
10 #include "xstd/h/iostream.h"
11 #include "xstd/h/iomanip.h"
12
13 #include "xstd/Assert.h"
14 #include "xstd/Time.h"
15 #include "xstd/xport.h"
16 #include "xstd/gadgets.h"
17
18
19 #if !defined(HAVE_GETTIMEOFDAY) && defined(HAVE__FTIME)
20 #include <sys/timeb.h>
21 static
gettimeofday(Time * tm,void *)22 void gettimeofday(Time *tm, void *) {
23 struct _timeb tb;
24 _ftime(&tb);
25 tm->tv_sec = tb.time;
26 tm->tv_usec = tb.millitm;
27 }
28 #endif
29
30
Now()31 Time Time::Now() {
32 Time tm;
33 gettimeofday(&tm, 0);
34
35 // Some Linux kernels have gettimeofday bugs that cause time jumps
36 // of approximately 72 minutes, especially on SMP systems. We saw it
37 // on an 8-CPU box running 2.6.18-8.el5. For 2002 discussion, start at
38 // http://www.kernel-traffic.org/kernel-traffic/kt20020708_174.html#1
39 // Here, we try to ignore individual jumps exceeding 60 minutes.
40 static Time ptm = tm; // previous time
41 if (tm.tv_sec - ptm.tv_sec > 3600L) {
42 clog << "Warning: ignoring " << (tm - ptm).secd() <<
43 "sec time jump" << endl <<
44 "\tfrom: " << ptm.tv_sec <<'.'<< ptm.tv_usec << endl <<
45 "\tto: " << tm.tv_sec << '.' << tm.tv_usec << endl;
46 const Time result = ptm;
47 ptm = tm; // if the strange value persists, honor it
48 return result;
49 }
50 ptm = tm;
51
52 return tm;
53 }
54
Max()55 Time Time::Max() {
56 return Time(INT_MAX, INT_MAX);
57 }
58
Msec(long msec)59 Time Time::Msec(long msec) {
60 return Time(msec / 1000, 1000*(msec % 1000));
61 }
62
Secd(double dsec)63 Time Time::Secd(double dsec) {
64 if (!Should(dsec <= LONG_MAX))
65 dsec = LONG_MAX;
66 else
67 if (!Should(dsec >= LONG_MIN))
68 dsec = LONG_MIN;
69 const long sec = (long)dsec;
70 return Time(sec, (long)((dsec-sec)*1e6));
71 }
72
Time(const struct tm & t)73 Time::Time(const struct tm &t) {
74 struct tm t2 = t; // must copy -- timegm modifies its param
75 if (t2.tm_year < 70) // a Y2K plug-in!
76 t2.tm_year += 100;
77 tv_sec = (0 <= t2.tm_mon && t2.tm_mon < 12) ? xtimegm(&t2) : -1;
78 tv_usec = tv_sec >= 0 ? 0 : -1;
79 }
80
operator +=(const Time & tm)81 Time &Time::operator +=(const Time &tm) {
82
83 tv_sec += tm.tv_sec;
84 tv_usec += tm.tv_usec;
85
86 if (tv_usec >= 1000000L) {
87 tv_usec -= 1000000L;
88 tv_sec++;
89 }
90
91 return *this;
92 }
93
94 // note: negative times are confusing for humans; e.g., "-1:1" means "-0.1"
operator -=(const Time & tm)95 Time &Time::operator -=(const Time &tm) {
96
97 tv_sec -= tm.tv_sec;
98 tv_usec -= tm.tv_usec;
99
100 if (tv_usec < 0) {
101 tv_usec += 1000000L;
102 tv_sec--;
103 }
104
105 return *this;
106 }
107
operator *=(int factor)108 Time &Time::operator *=(int factor) {
109 tv_sec *= factor;
110 tv_usec *= factor;
111
112 if (tv_usec >= 1000000L) {
113 tv_sec += tv_usec/1000000L;
114 tv_usec %= 1000000L;
115 } else
116 if (tv_usec < 0) {
117 tv_usec = -tv_usec;
118 tv_sec -= tv_usec/1000000L;
119 tv_sec--;
120 tv_usec = 1000000L - (tv_usec % 1000000L);
121 }
122
123 return *this;
124 }
125
operator /=(double factor)126 Time &Time::operator /=(double factor) {
127 if (factor) {
128 const double dsec = secd()/factor;
129 tv_sec = (long) dsec;
130 tv_usec = (long)((dsec-tv_sec)*1e6);
131 } else {
132 tv_sec = tv_usec = -1;
133 }
134
135 return *this;
136 }
137
gmtime() const138 struct tm *Time::gmtime() const {
139 time_t clock = (time_t) tv_sec;
140 return ::gmtime(&clock);
141 }
142
read(istream & is)143 istream &Time::read(istream &is) {
144 char c;
145 return is >> tv_sec >> c >> tv_usec;
146 }
147
print(ostream & os) const148 ostream &Time::print(ostream &os) const {
149 if (tv_sec < 60*60*24*365 && tv_usec >= 0)
150 return printInterval(os);
151 if (tv_sec == -1 && tv_usec == -1)
152 return os << "<none>"; // works for everybody?
153
154 const char osfill = os.fill();
155 return os << tv_sec << '.' << setw(6) << setfill('0') << tv_usec << setfill(osfill);
156 }
157
printInterval(ostream & os) const158 ostream &Time::printInterval(ostream &os) const {
159
160 const int osprec = os.precision(2);
161 const char osfill = os.fill();
162
163 if (tv_sec < 0)
164 os << tv_sec << '.' << setfill('0') << setw(6) << tv_usec << "sec";
165 else
166 if (tv_sec == 0)
167 if (tv_usec < 1000)
168 os << tv_usec << "usec";
169 else
170 os << (tv_usec/1000) << "msec";
171 else
172 if (tv_sec < 60)
173 os << secd() << "sec";
174 else
175 if (tv_sec < 60*60)
176 os << secd()/60 << "min";
177 else
178 if (tv_sec < 24*60*60)
179 os << secd()/(60*60) << "hour";
180 else
181 if (tv_sec < 365*24*60*60)
182 os << secd()/(24*60*60) << "day";
183 else
184 os << secd()/(365*24*60*60) << "year";
185
186 os.fill(osfill);
187 os.precision(osprec);
188
189 return os;
190 }
191
192 // useful for debugging
operator <<(ostream & os,const struct tm & t)193 ostream &operator <<(ostream &os, const struct tm &t) {
194 return os << here << endl
195 << '\t' << "tm_mday: " << "\t " << setw(4) << t.tm_mday << endl
196 << '\t' << "tm_mon: " << "\t " << setw(4) << t.tm_mon << endl
197 << '\t' << "tm_year: " << "\t " << setw(4) << t.tm_year << endl
198 << '\t' << "tm_hour: " << "\t " << setw(4) << t.tm_hour << endl
199 << '\t' << "tm_min: " << "\t " << setw(4) << t.tm_min << endl
200 << '\t' << "tm_sec: " << "\t " << setw(4) << t.tm_sec << endl
201 << '\t' << "tv_sec: " << "\t " << setw(4) << Time(t) << endl
202 << endl;
203 }
204