1 // Copyright 2010 The Kyua Authors.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 #include "utils/datetime.hpp"
30
31 extern "C" {
32 #include <sys/time.h>
33
34 #include <time.h>
35 }
36
37 #include <stdexcept>
38
39 #include "utils/format/macros.hpp"
40 #include "utils/optional.ipp"
41 #include "utils/noncopyable.hpp"
42 #include "utils/sanity.hpp"
43
44 namespace datetime = utils::datetime;
45
46 using utils::none;
47 using utils::optional;
48
49
50 namespace {
51
52
53 /// Fake value for the current time.
54 static optional< datetime::timestamp > mock_now = none;
55
56
57 } // anonymous namespace
58
59
60 /// Creates a zero time delta.
delta(void)61 datetime::delta::delta(void) :
62 seconds(0),
63 useconds(0)
64 {
65 }
66
67
68 /// Creates a time delta.
69 ///
70 /// \param seconds_ The seconds in the delta.
71 /// \param useconds_ The microseconds in the delta.
72 ///
73 /// \throw std::runtime_error If the input delta is negative.
delta(const int64_t seconds_,const unsigned long useconds_)74 datetime::delta::delta(const int64_t seconds_,
75 const unsigned long useconds_) :
76 seconds(seconds_),
77 useconds(useconds_)
78 {
79 if (seconds_ < 0) {
80 throw std::runtime_error(F("Negative deltas are not supported by the "
81 "datetime::delta class; got: %s") % (*this));
82 }
83 }
84
85
86 /// Converts a time expressed in microseconds to a delta.
87 ///
88 /// \param useconds The amount of microseconds representing the delta.
89 ///
90 /// \return A new delta object.
91 ///
92 /// \throw std::runtime_error If the input delta is negative.
93 datetime::delta
from_microseconds(const int64_t useconds)94 datetime::delta::from_microseconds(const int64_t useconds)
95 {
96 if (useconds < 0) {
97 throw std::runtime_error(F("Negative deltas are not supported by the "
98 "datetime::delta class; got: %sus") %
99 useconds);
100 }
101
102 return delta(useconds / 1000000, useconds % 1000000);
103 }
104
105
106 /// Convers the delta to a flat representation expressed in microseconds.
107 ///
108 /// \return The amount of microseconds that corresponds to this delta.
109 int64_t
to_microseconds(void) const110 datetime::delta::to_microseconds(void) const
111 {
112 return seconds * 1000000 + useconds;
113 }
114
115
116 /// Checks if two time deltas are equal.
117 ///
118 /// \param other The object to compare to.
119 ///
120 /// \return True if the two time deltas are equals; false otherwise.
121 bool
operator ==(const datetime::delta & other) const122 datetime::delta::operator==(const datetime::delta& other) const
123 {
124 return seconds == other.seconds && useconds == other.useconds;
125 }
126
127
128 /// Checks if two time deltas are different.
129 ///
130 /// \param other The object to compare to.
131 ///
132 /// \return True if the two time deltas are different; false otherwise.
133 bool
operator !=(const datetime::delta & other) const134 datetime::delta::operator!=(const datetime::delta& other) const
135 {
136 return !(*this == other);
137 }
138
139
140 /// Checks if this time delta is shorter than another one.
141 ///
142 /// \param other The object to compare to.
143 ///
144 /// \return True if this time delta is shorter than other; false otherwise.
145 bool
operator <(const datetime::delta & other) const146 datetime::delta::operator<(const datetime::delta& other) const
147 {
148 return seconds < other.seconds ||
149 (seconds == other.seconds && useconds < other.useconds);
150 }
151
152
153 /// Checks if this time delta is shorter than or equal to another one.
154 ///
155 /// \param other The object to compare to.
156 ///
157 /// \return True if this time delta is shorter than or equal to; false
158 /// otherwise.
159 bool
operator <=(const datetime::delta & other) const160 datetime::delta::operator<=(const datetime::delta& other) const
161 {
162 return (*this) < other || (*this) == other;
163 }
164
165
166 /// Checks if this time delta is larger than another one.
167 ///
168 /// \param other The object to compare to.
169 ///
170 /// \return True if this time delta is larger than other; false otherwise.
171 bool
operator >(const datetime::delta & other) const172 datetime::delta::operator>(const datetime::delta& other) const
173 {
174 return seconds > other.seconds ||
175 (seconds == other.seconds && useconds > other.useconds);
176 }
177
178
179 /// Checks if this time delta is larger than or equal to another one.
180 ///
181 /// \param other The object to compare to.
182 ///
183 /// \return True if this time delta is larger than or equal to; false
184 /// otherwise.
185 bool
operator >=(const datetime::delta & other) const186 datetime::delta::operator>=(const datetime::delta& other) const
187 {
188 return (*this) > other || (*this) == other;
189 }
190
191
192 /// Adds a time delta to this one.
193 ///
194 /// \param other The time delta to add.
195 ///
196 /// \return The addition of this time delta with the other time delta.
197 datetime::delta
operator +(const datetime::delta & other) const198 datetime::delta::operator+(const datetime::delta& other) const
199 {
200 return delta::from_microseconds(to_microseconds() +
201 other.to_microseconds());
202 }
203
204
205 /// Adds a time delta to this one and updates this with the result.
206 ///
207 /// \param other The time delta to add.
208 ///
209 /// \return The addition of this time delta with the other time delta.
210 datetime::delta&
operator +=(const datetime::delta & other)211 datetime::delta::operator+=(const datetime::delta& other)
212 {
213 *this = *this + other;
214 return *this;
215 }
216
217
218 /// Scales this delta by a positive integral factor.
219 ///
220 /// \param factor The scaling factor.
221 ///
222 /// \return The scaled delta.
223 datetime::delta
operator *(const std::size_t factor) const224 datetime::delta::operator*(const std::size_t factor) const
225 {
226 return delta::from_microseconds(to_microseconds() * factor);
227 }
228
229
230 /// Scales this delta by and updates this delta with the result.
231 ///
232 /// \param factor The scaling factor.
233 ///
234 /// \return The scaled delta as a reference to the input object.
235 datetime::delta&
operator *=(const std::size_t factor)236 datetime::delta::operator*=(const std::size_t factor)
237 {
238 *this = *this * factor;
239 return *this;
240 }
241
242
243 /// Injects the object into a stream.
244 ///
245 /// \param output The stream into which to inject the object.
246 /// \param object The object to format.
247 ///
248 /// \return The output stream.
249 std::ostream&
operator <<(std::ostream & output,const delta & object)250 datetime::operator<<(std::ostream& output, const delta& object)
251 {
252 return (output << object.to_microseconds() << "us");
253 }
254
255
256 namespace utils {
257 namespace datetime {
258
259
260 /// Internal representation for datetime::timestamp.
261 struct timestamp::impl : utils::noncopyable {
262 /// The raw timestamp as provided by libc.
263 ::timeval data;
264
265 /// Constructs an impl object from initialized data.
266 ///
267 /// \param data_ The raw timestamp to use.
implutils::datetime::timestamp::impl268 impl(const ::timeval& data_) : data(data_)
269 {
270 }
271 };
272
273
274 } // namespace datetime
275 } // namespace utils
276
277
278 /// Constructs a new timestamp.
279 ///
280 /// \param pimpl_ An existing impl representation.
timestamp(std::shared_ptr<impl> pimpl_)281 datetime::timestamp::timestamp(std::shared_ptr< impl > pimpl_) :
282 _pimpl(pimpl_)
283 {
284 }
285
286
287 /// Constructs a timestamp from the amount of microseconds since the epoch.
288 ///
289 /// \param value Microseconds since the epoch in UTC. Must be positive.
290 ///
291 /// \return A new timestamp.
292 datetime::timestamp
from_microseconds(const int64_t value)293 datetime::timestamp::from_microseconds(const int64_t value)
294 {
295 PRE(value >= 0);
296 ::timeval data;
297 data.tv_sec = static_cast< time_t >(value / 1000000);
298 data.tv_usec = static_cast< suseconds_t >(value % 1000000);
299 return timestamp(std::shared_ptr< impl >(new impl(data)));
300 }
301
302
303 /// Constructs a timestamp based on user-friendly values.
304 ///
305 /// \param year The year in the [1900,inf) range.
306 /// \param month The month in the [1,12] range.
307 /// \param day The day in the [1,30] range.
308 /// \param hour The hour in the [0,23] range.
309 /// \param minute The minute in the [0,59] range.
310 /// \param second The second in the [0,60] range. Yes, that is 60, which can be
311 /// the case on leap seconds.
312 /// \param microsecond The microsecond in the [0,999999] range.
313 ///
314 /// \return A new timestamp.
315 datetime::timestamp
from_values(const int year,const int month,const int day,const int hour,const int minute,const int second,const int microsecond)316 datetime::timestamp::from_values(const int year, const int month,
317 const int day, const int hour,
318 const int minute, const int second,
319 const int microsecond)
320 {
321 PRE(year >= 1900);
322 PRE(month >= 1 && month <= 12);
323 PRE(day >= 1 && day <= 30);
324 PRE(hour >= 0 && hour <= 23);
325 PRE(minute >= 0 && minute <= 59);
326 PRE(second >= 0 && second <= 60);
327 PRE(microsecond >= 0 && microsecond <= 999999);
328
329 // The code below is quite convoluted. The problem is that we can't assume
330 // that some fields (like tm_zone) of ::tm exist, and thus we can't blindly
331 // set them from the code. Instead of detecting their presence in the
332 // configure script, we just query the current time to initialize such
333 // fields and then we override the ones we are interested in. (There might
334 // be some better way to do this, but I don't know it and the documentation
335 // does not shed much light into how to create your own fake date.)
336
337 const time_t current_time = ::time(NULL);
338
339 ::tm timedata;
340 if (::gmtime_r(¤t_time, &timedata) == NULL)
341 UNREACHABLE;
342
343 timedata.tm_sec = second;
344 timedata.tm_min = minute;
345 timedata.tm_hour = hour;
346 timedata.tm_mday = day;
347 timedata.tm_mon = month - 1;
348 timedata.tm_year = year - 1900;
349 // Ignored: timedata.tm_wday
350 // Ignored: timedata.tm_yday
351
352 ::timeval data;
353 data.tv_sec = ::mktime(&timedata);
354 data.tv_usec = static_cast< suseconds_t >(microsecond);
355 return timestamp(std::shared_ptr< impl >(new impl(data)));
356 }
357
358
359 /// Constructs a new timestamp representing the current time in UTC.
360 ///
361 /// \return A new timestamp.
362 datetime::timestamp
now(void)363 datetime::timestamp::now(void)
364 {
365 if (mock_now)
366 return mock_now.get();
367
368 ::timeval data;
369 {
370 const int ret = ::gettimeofday(&data, NULL);
371 INV(ret != -1);
372 }
373
374 return timestamp(std::shared_ptr< impl >(new impl(data)));
375 }
376
377
378 /// Formats a timestamp.
379 ///
380 /// \param format The format string to use as consumed by strftime(3).
381 ///
382 /// \return The formatted time.
383 std::string
strftime(const std::string & format) const384 datetime::timestamp::strftime(const std::string& format) const
385 {
386 ::tm timedata;
387 // This conversion to time_t is necessary because tv_sec is not guaranteed
388 // to be a time_t. For example, it isn't in NetBSD 5.x
389 ::time_t epoch_seconds;
390 epoch_seconds = _pimpl->data.tv_sec;
391 if (::gmtime_r(&epoch_seconds, &timedata) == NULL)
392 UNREACHABLE_MSG("gmtime_r(3) did not accept the value returned by "
393 "gettimeofday(2)");
394
395 char buf[128];
396 if (::strftime(buf, sizeof(buf), format.c_str(), &timedata) == 0)
397 UNREACHABLE_MSG("Arbitrary-long format strings are unimplemented");
398 return buf;
399 }
400
401
402 /// Formats a timestamp with the ISO 8601 standard and in UTC.
403 ///
404 /// \return A string with the formatted timestamp.
405 std::string
to_iso8601_in_utc(void) const406 datetime::timestamp::to_iso8601_in_utc(void) const
407 {
408 return F("%s.%06sZ") % strftime("%Y-%m-%dT%H:%M:%S") % _pimpl->data.tv_usec;
409 }
410
411
412 /// Returns the number of microseconds since the epoch in UTC.
413 ///
414 /// \return A number of microseconds.
415 int64_t
to_microseconds(void) const416 datetime::timestamp::to_microseconds(void) const
417 {
418 return static_cast< int64_t >(_pimpl->data.tv_sec) * 1000000 +
419 _pimpl->data.tv_usec;
420 }
421
422
423 /// Returns the number of seconds since the epoch in UTC.
424 ///
425 /// \return A number of seconds.
426 int64_t
to_seconds(void) const427 datetime::timestamp::to_seconds(void) const
428 {
429 return static_cast< int64_t >(_pimpl->data.tv_sec);
430 }
431
432
433 /// Sets the current time for testing purposes.
434 void
set_mock_now(const int year,const int month,const int day,const int hour,const int minute,const int second,const int microsecond)435 datetime::set_mock_now(const int year, const int month,
436 const int day, const int hour,
437 const int minute, const int second,
438 const int microsecond)
439 {
440 mock_now = timestamp::from_values(year, month, day, hour, minute, second,
441 microsecond);
442 }
443
444
445 /// Sets the current time for testing purposes.
446 ///
447 /// \param mock_now_ The mock timestamp to set the time to.
448 void
set_mock_now(const timestamp & mock_now_)449 datetime::set_mock_now(const timestamp& mock_now_)
450 {
451 mock_now = mock_now_;
452 }
453
454
455 /// Checks if two timestamps are equal.
456 ///
457 /// \param other The object to compare to.
458 ///
459 /// \return True if the two timestamps are equals; false otherwise.
460 bool
operator ==(const datetime::timestamp & other) const461 datetime::timestamp::operator==(const datetime::timestamp& other) const
462 {
463 return _pimpl->data.tv_sec == other._pimpl->data.tv_sec &&
464 _pimpl->data.tv_usec == other._pimpl->data.tv_usec;
465 }
466
467
468 /// Checks if two timestamps are different.
469 ///
470 /// \param other The object to compare to.
471 ///
472 /// \return True if the two timestamps are different; false otherwise.
473 bool
operator !=(const datetime::timestamp & other) const474 datetime::timestamp::operator!=(const datetime::timestamp& other) const
475 {
476 return !(*this == other);
477 }
478
479
480 /// Checks if a timestamp is before another.
481 ///
482 /// \param other The object to compare to.
483 ///
484 /// \return True if this timestamp comes before other; false otherwise.
485 bool
operator <(const datetime::timestamp & other) const486 datetime::timestamp::operator<(const datetime::timestamp& other) const
487 {
488 return to_microseconds() < other.to_microseconds();
489 }
490
491
492 /// Checks if a timestamp is before or equal to another.
493 ///
494 /// \param other The object to compare to.
495 ///
496 /// \return True if this timestamp comes before other or is equal to it;
497 /// false otherwise.
498 bool
operator <=(const datetime::timestamp & other) const499 datetime::timestamp::operator<=(const datetime::timestamp& other) const
500 {
501 return to_microseconds() <= other.to_microseconds();
502 }
503
504
505 /// Checks if a timestamp is after another.
506 ///
507 /// \param other The object to compare to.
508 ///
509 /// \return True if this timestamp comes after other; false otherwise;
510 bool
operator >(const datetime::timestamp & other) const511 datetime::timestamp::operator>(const datetime::timestamp& other) const
512 {
513 return to_microseconds() > other.to_microseconds();
514 }
515
516
517 /// Checks if a timestamp is after or equal to another.
518 ///
519 /// \param other The object to compare to.
520 ///
521 /// \return True if this timestamp comes after other or is equal to it;
522 /// false otherwise.
523 bool
operator >=(const datetime::timestamp & other) const524 datetime::timestamp::operator>=(const datetime::timestamp& other) const
525 {
526 return to_microseconds() >= other.to_microseconds();
527 }
528
529
530 /// Calculates the addition of a delta to a timestamp.
531 ///
532 /// \param other The delta to add.
533 ///
534 /// \return A new timestamp in the future.
535 datetime::timestamp
operator +(const datetime::delta & other) const536 datetime::timestamp::operator+(const datetime::delta& other) const
537 {
538 return datetime::timestamp::from_microseconds(to_microseconds() +
539 other.to_microseconds());
540 }
541
542
543 /// Calculates the addition of a delta to this timestamp.
544 ///
545 /// \param other The delta to add.
546 ///
547 /// \return A reference to the modified timestamp.
548 datetime::timestamp&
operator +=(const datetime::delta & other)549 datetime::timestamp::operator+=(const datetime::delta& other)
550 {
551 *this = *this + other;
552 return *this;
553 }
554
555
556 /// Calculates the subtraction of a delta from a timestamp.
557 ///
558 /// \param other The delta to subtract.
559 ///
560 /// \return A new timestamp in the past.
561 datetime::timestamp
operator -(const datetime::delta & other) const562 datetime::timestamp::operator-(const datetime::delta& other) const
563 {
564 return datetime::timestamp::from_microseconds(to_microseconds() -
565 other.to_microseconds());
566 }
567
568
569 /// Calculates the subtraction of a delta from this timestamp.
570 ///
571 /// \param other The delta to subtract.
572 ///
573 /// \return A reference to the modified timestamp.
574 datetime::timestamp&
operator -=(const datetime::delta & other)575 datetime::timestamp::operator-=(const datetime::delta& other)
576 {
577 *this = *this - other;
578 return *this;
579 }
580
581
582 /// Calculates the delta between two timestamps.
583 ///
584 /// \param other The subtrahend.
585 ///
586 /// \return The difference between this object and the other object.
587 ///
588 /// \throw std::runtime_error If the subtraction would result in a negative time
589 /// delta, which are currently not supported.
590 datetime::delta
operator -(const datetime::timestamp & other) const591 datetime::timestamp::operator-(const datetime::timestamp& other) const
592 {
593 /*
594 * XXX-BD: gettimeofday isn't necessarily monotonic so return the
595 * smallest non-zero delta if time went backwards.
596 */
597 if ((*this) < other)
598 return datetime::delta::from_microseconds(1);
599 return datetime::delta::from_microseconds(to_microseconds() -
600 other.to_microseconds());
601 }
602
603
604 /// Injects the object into a stream.
605 ///
606 /// \param output The stream into which to inject the object.
607 /// \param object The object to format.
608 ///
609 /// \return The output stream.
610 std::ostream&
operator <<(std::ostream & output,const timestamp & object)611 datetime::operator<<(std::ostream& output, const timestamp& object)
612 {
613 return (output << object.to_microseconds() << "us");
614 }
615