1 // Copyright 2010 The Kyua Authors.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
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.
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.
29 #include "utils/datetime.hpp"
39 #include "utils/format/macros.hpp"
40 #include "utils/optional.ipp"
41 #include "utils/noncopyable.hpp"
42 #include "utils/sanity.hpp"
44 namespace datetime = utils::datetime;
47 using utils::optional;
53 /// Fake value for the current time.
54 static optional< datetime::timestamp > mock_now = none;
57 } // anonymous namespace
60 /// Creates a zero time delta.
61 datetime::delta::delta(void) :
68 /// Creates a time delta.
70 /// \param seconds_ The seconds in the delta.
71 /// \param useconds_ The microseconds in the delta.
73 /// \throw std::runtime_error If the input delta is negative.
74 datetime::delta::delta(const int64_t seconds_,
75 const unsigned long useconds_) :
80 throw std::runtime_error(F("Negative deltas are not supported by the "
81 "datetime::delta class; got: %s") % (*this));
86 /// Converts a time expressed in microseconds to a delta.
88 /// \param useconds The amount of microseconds representing the delta.
90 /// \return A new delta object.
92 /// \throw std::runtime_error If the input delta is negative.
94 datetime::delta::from_microseconds(const int64_t useconds)
97 throw std::runtime_error(F("Negative deltas are not supported by the "
98 "datetime::delta class; got: %sus") %
102 return delta(useconds / 1000000, useconds % 1000000);
106 /// Convers the delta to a flat representation expressed in microseconds.
108 /// \return The amount of microseconds that corresponds to this delta.
110 datetime::delta::to_microseconds(void) const
112 return seconds * 1000000 + useconds;
116 /// Checks if two time deltas are equal.
118 /// \param other The object to compare to.
120 /// \return True if the two time deltas are equals; false otherwise.
122 datetime::delta::operator==(const datetime::delta& other) const
124 return seconds == other.seconds && useconds == other.useconds;
128 /// Checks if two time deltas are different.
130 /// \param other The object to compare to.
132 /// \return True if the two time deltas are different; false otherwise.
134 datetime::delta::operator!=(const datetime::delta& other) const
136 return !(*this == other);
140 /// Checks if this time delta is shorter than another one.
142 /// \param other The object to compare to.
144 /// \return True if this time delta is shorter than other; false otherwise.
146 datetime::delta::operator<(const datetime::delta& other) const
148 return seconds < other.seconds ||
149 (seconds == other.seconds && useconds < other.useconds);
153 /// Checks if this time delta is shorter than or equal to another one.
155 /// \param other The object to compare to.
157 /// \return True if this time delta is shorter than or equal to; false
160 datetime::delta::operator<=(const datetime::delta& other) const
162 return (*this) < other || (*this) == other;
166 /// Checks if this time delta is larger than another one.
168 /// \param other The object to compare to.
170 /// \return True if this time delta is larger than other; false otherwise.
172 datetime::delta::operator>(const datetime::delta& other) const
174 return seconds > other.seconds ||
175 (seconds == other.seconds && useconds > other.useconds);
179 /// Checks if this time delta is larger than or equal to another one.
181 /// \param other The object to compare to.
183 /// \return True if this time delta is larger than or equal to; false
186 datetime::delta::operator>=(const datetime::delta& other) const
188 return (*this) > other || (*this) == other;
192 /// Adds a time delta to this one.
194 /// \param other The time delta to add.
196 /// \return The addition of this time delta with the other time delta.
198 datetime::delta::operator+(const datetime::delta& other) const
200 return delta::from_microseconds(to_microseconds() +
201 other.to_microseconds());
205 /// Adds a time delta to this one and updates this with the result.
207 /// \param other The time delta to add.
209 /// \return The addition of this time delta with the other time delta.
211 datetime::delta::operator+=(const datetime::delta& other)
213 *this = *this + other;
218 /// Scales this delta by a positive integral factor.
220 /// \param factor The scaling factor.
222 /// \return The scaled delta.
224 datetime::delta::operator*(const std::size_t factor) const
226 return delta::from_microseconds(to_microseconds() * factor);
230 /// Scales this delta by and updates this delta with the result.
232 /// \param factor The scaling factor.
234 /// \return The scaled delta as a reference to the input object.
236 datetime::delta::operator*=(const std::size_t factor)
238 *this = *this * factor;
243 /// Injects the object into a stream.
245 /// \param output The stream into which to inject the object.
246 /// \param object The object to format.
248 /// \return The output stream.
250 datetime::operator<<(std::ostream& output, const delta& object)
252 return (output << object.to_microseconds() << "us");
260 /// Internal representation for datetime::timestamp.
261 struct timestamp::impl : utils::noncopyable {
262 /// The raw timestamp as provided by libc.
265 /// Constructs an impl object from initialized data.
267 /// \param data_ The raw timestamp to use.
268 impl(const ::timeval& data_) : data(data_)
274 } // namespace datetime
278 /// Constructs a new timestamp.
280 /// \param pimpl_ An existing impl representation.
281 datetime::timestamp::timestamp(std::shared_ptr< impl > pimpl_) :
287 /// Constructs a timestamp from the amount of microseconds since the epoch.
289 /// \param value Microseconds since the epoch in UTC. Must be positive.
291 /// \return A new timestamp.
293 datetime::timestamp::from_microseconds(const int64_t value)
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)));
303 /// Constructs a timestamp based on user-friendly values.
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.
314 /// \return A new timestamp.
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)
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);
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.)
337 const time_t current_time = ::time(NULL);
340 if (::gmtime_r(¤t_time, &timedata) == NULL)
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
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)));
359 /// Constructs a new timestamp representing the current time in UTC.
361 /// \return A new timestamp.
363 datetime::timestamp::now(void)
366 return mock_now.get();
370 const int ret = ::gettimeofday(&data, NULL);
374 return timestamp(std::shared_ptr< impl >(new impl(data)));
378 /// Formats a timestamp.
380 /// \param format The format string to use as consumed by strftime(3).
382 /// \return The formatted time.
384 datetime::timestamp::strftime(const std::string& format) const
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 "
396 if (::strftime(buf, sizeof(buf), format.c_str(), &timedata) == 0)
397 UNREACHABLE_MSG("Arbitrary-long format strings are unimplemented");
402 /// Formats a timestamp with the ISO 8601 standard and in UTC.
404 /// \return A string with the formatted timestamp.
406 datetime::timestamp::to_iso8601_in_utc(void) const
408 return F("%s.%06sZ") % strftime("%Y-%m-%dT%H:%M:%S") % _pimpl->data.tv_usec;
412 /// Returns the number of microseconds since the epoch in UTC.
414 /// \return A number of microseconds.
416 datetime::timestamp::to_microseconds(void) const
418 return static_cast< int64_t >(_pimpl->data.tv_sec) * 1000000 +
419 _pimpl->data.tv_usec;
423 /// Returns the number of seconds since the epoch in UTC.
425 /// \return A number of seconds.
427 datetime::timestamp::to_seconds(void) const
429 return static_cast< int64_t >(_pimpl->data.tv_sec);
433 /// Sets the current time for testing purposes.
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)
440 mock_now = timestamp::from_values(year, month, day, hour, minute, second,
445 /// Sets the current time for testing purposes.
447 /// \param mock_now_ The mock timestamp to set the time to.
449 datetime::set_mock_now(const timestamp& mock_now_)
451 mock_now = mock_now_;
455 /// Checks if two timestamps are equal.
457 /// \param other The object to compare to.
459 /// \return True if the two timestamps are equals; false otherwise.
461 datetime::timestamp::operator==(const datetime::timestamp& other) const
463 return _pimpl->data.tv_sec == other._pimpl->data.tv_sec &&
464 _pimpl->data.tv_usec == other._pimpl->data.tv_usec;
468 /// Checks if two timestamps are different.
470 /// \param other The object to compare to.
472 /// \return True if the two timestamps are different; false otherwise.
474 datetime::timestamp::operator!=(const datetime::timestamp& other) const
476 return !(*this == other);
480 /// Checks if a timestamp is before another.
482 /// \param other The object to compare to.
484 /// \return True if this timestamp comes before other; false otherwise.
486 datetime::timestamp::operator<(const datetime::timestamp& other) const
488 return to_microseconds() < other.to_microseconds();
492 /// Checks if a timestamp is before or equal to another.
494 /// \param other The object to compare to.
496 /// \return True if this timestamp comes before other or is equal to it;
499 datetime::timestamp::operator<=(const datetime::timestamp& other) const
501 return to_microseconds() <= other.to_microseconds();
505 /// Checks if a timestamp is after another.
507 /// \param other The object to compare to.
509 /// \return True if this timestamp comes after other; false otherwise;
511 datetime::timestamp::operator>(const datetime::timestamp& other) const
513 return to_microseconds() > other.to_microseconds();
517 /// Checks if a timestamp is after or equal to another.
519 /// \param other The object to compare to.
521 /// \return True if this timestamp comes after other or is equal to it;
524 datetime::timestamp::operator>=(const datetime::timestamp& other) const
526 return to_microseconds() >= other.to_microseconds();
530 /// Calculates the addition of a delta to a timestamp.
532 /// \param other The delta to add.
534 /// \return A new timestamp in the future.
536 datetime::timestamp::operator+(const datetime::delta& other) const
538 return datetime::timestamp::from_microseconds(to_microseconds() +
539 other.to_microseconds());
543 /// Calculates the addition of a delta to this timestamp.
545 /// \param other The delta to add.
547 /// \return A reference to the modified timestamp.
549 datetime::timestamp::operator+=(const datetime::delta& other)
551 *this = *this + other;
556 /// Calculates the subtraction of a delta from a timestamp.
558 /// \param other The delta to subtract.
560 /// \return A new timestamp in the past.
562 datetime::timestamp::operator-(const datetime::delta& other) const
564 return datetime::timestamp::from_microseconds(to_microseconds() -
565 other.to_microseconds());
569 /// Calculates the subtraction of a delta from this timestamp.
571 /// \param other The delta to subtract.
573 /// \return A reference to the modified timestamp.
575 datetime::timestamp::operator-=(const datetime::delta& other)
577 *this = *this - other;
582 /// Calculates the delta between two timestamps.
584 /// \param other The subtrahend.
586 /// \return The difference between this object and the other object.
588 /// \throw std::runtime_error If the subtraction would result in a negative time
589 /// delta, which are currently not supported.
591 datetime::timestamp::operator-(const datetime::timestamp& other) const
593 if ((*this) < other) {
594 throw std::runtime_error(
595 F("Cannot subtract %s from %s as it would result in a negative "
596 "datetime::delta, which are not supported") % other % (*this));
598 return datetime::delta::from_microseconds(to_microseconds() -
599 other.to_microseconds());
603 /// Injects the object into a stream.
605 /// \param output The stream into which to inject the object.
606 /// \param object The object to format.
608 /// \return The output stream.
610 datetime::operator<<(std::ostream& output, const timestamp& object)
612 return (output << object.to_microseconds() << "us");