108334c51SBrooks Davis // Copyright 2010 The Kyua Authors.
208334c51SBrooks Davis // All rights reserved.
308334c51SBrooks Davis //
408334c51SBrooks Davis // Redistribution and use in source and binary forms, with or without
508334c51SBrooks Davis // modification, are permitted provided that the following conditions are
608334c51SBrooks Davis // met:
708334c51SBrooks Davis //
808334c51SBrooks Davis // * Redistributions of source code must retain the above copyright
908334c51SBrooks Davis // notice, this list of conditions and the following disclaimer.
1008334c51SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
1108334c51SBrooks Davis // notice, this list of conditions and the following disclaimer in the
1208334c51SBrooks Davis // documentation and/or other materials provided with the distribution.
1308334c51SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
1408334c51SBrooks Davis // may be used to endorse or promote products derived from this software
1508334c51SBrooks Davis // without specific prior written permission.
1608334c51SBrooks Davis //
1708334c51SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1808334c51SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1908334c51SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2008334c51SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2108334c51SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2208334c51SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2308334c51SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2408334c51SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2508334c51SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2608334c51SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2708334c51SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2808334c51SBrooks Davis
2908334c51SBrooks Davis #include "utils/datetime.hpp"
3008334c51SBrooks Davis
3108334c51SBrooks Davis extern "C" {
3208334c51SBrooks Davis #include <sys/time.h>
3308334c51SBrooks Davis
3408334c51SBrooks Davis #include <time.h>
3508334c51SBrooks Davis }
3608334c51SBrooks Davis
3708334c51SBrooks Davis #include <stdexcept>
3808334c51SBrooks Davis
3908334c51SBrooks Davis #include "utils/format/macros.hpp"
4008334c51SBrooks Davis #include "utils/optional.ipp"
4108334c51SBrooks Davis #include "utils/noncopyable.hpp"
4208334c51SBrooks Davis #include "utils/sanity.hpp"
4308334c51SBrooks Davis
4408334c51SBrooks Davis namespace datetime = utils::datetime;
4508334c51SBrooks Davis
4608334c51SBrooks Davis using utils::none;
4708334c51SBrooks Davis using utils::optional;
4808334c51SBrooks Davis
4908334c51SBrooks Davis
5008334c51SBrooks Davis namespace {
5108334c51SBrooks Davis
5208334c51SBrooks Davis
5308334c51SBrooks Davis /// Fake value for the current time.
5408334c51SBrooks Davis static optional< datetime::timestamp > mock_now = none;
5508334c51SBrooks Davis
5608334c51SBrooks Davis
5708334c51SBrooks Davis } // anonymous namespace
5808334c51SBrooks Davis
5908334c51SBrooks Davis
6008334c51SBrooks Davis /// Creates a zero time delta.
delta(void)6108334c51SBrooks Davis datetime::delta::delta(void) :
6208334c51SBrooks Davis seconds(0),
6308334c51SBrooks Davis useconds(0)
6408334c51SBrooks Davis {
6508334c51SBrooks Davis }
6608334c51SBrooks Davis
6708334c51SBrooks Davis
6808334c51SBrooks Davis /// Creates a time delta.
6908334c51SBrooks Davis ///
7008334c51SBrooks Davis /// \param seconds_ The seconds in the delta.
7108334c51SBrooks Davis /// \param useconds_ The microseconds in the delta.
7208334c51SBrooks Davis ///
7308334c51SBrooks Davis /// \throw std::runtime_error If the input delta is negative.
delta(const int64_t seconds_,const unsigned long useconds_)7408334c51SBrooks Davis datetime::delta::delta(const int64_t seconds_,
7508334c51SBrooks Davis const unsigned long useconds_) :
7608334c51SBrooks Davis seconds(seconds_),
7708334c51SBrooks Davis useconds(useconds_)
7808334c51SBrooks Davis {
7908334c51SBrooks Davis if (seconds_ < 0) {
8008334c51SBrooks Davis throw std::runtime_error(F("Negative deltas are not supported by the "
8108334c51SBrooks Davis "datetime::delta class; got: %s") % (*this));
8208334c51SBrooks Davis }
8308334c51SBrooks Davis }
8408334c51SBrooks Davis
8508334c51SBrooks Davis
8608334c51SBrooks Davis /// Converts a time expressed in microseconds to a delta.
8708334c51SBrooks Davis ///
8808334c51SBrooks Davis /// \param useconds The amount of microseconds representing the delta.
8908334c51SBrooks Davis ///
9008334c51SBrooks Davis /// \return A new delta object.
9108334c51SBrooks Davis ///
9208334c51SBrooks Davis /// \throw std::runtime_error If the input delta is negative.
9308334c51SBrooks Davis datetime::delta
from_microseconds(const int64_t useconds)9408334c51SBrooks Davis datetime::delta::from_microseconds(const int64_t useconds)
9508334c51SBrooks Davis {
9608334c51SBrooks Davis if (useconds < 0) {
9708334c51SBrooks Davis throw std::runtime_error(F("Negative deltas are not supported by the "
9808334c51SBrooks Davis "datetime::delta class; got: %sus") %
9908334c51SBrooks Davis useconds);
10008334c51SBrooks Davis }
10108334c51SBrooks Davis
10208334c51SBrooks Davis return delta(useconds / 1000000, useconds % 1000000);
10308334c51SBrooks Davis }
10408334c51SBrooks Davis
10508334c51SBrooks Davis
10608334c51SBrooks Davis /// Convers the delta to a flat representation expressed in microseconds.
10708334c51SBrooks Davis ///
10808334c51SBrooks Davis /// \return The amount of microseconds that corresponds to this delta.
10908334c51SBrooks Davis int64_t
to_microseconds(void) const11008334c51SBrooks Davis datetime::delta::to_microseconds(void) const
11108334c51SBrooks Davis {
11208334c51SBrooks Davis return seconds * 1000000 + useconds;
11308334c51SBrooks Davis }
11408334c51SBrooks Davis
11508334c51SBrooks Davis
11608334c51SBrooks Davis /// Checks if two time deltas are equal.
11708334c51SBrooks Davis ///
11808334c51SBrooks Davis /// \param other The object to compare to.
11908334c51SBrooks Davis ///
12008334c51SBrooks Davis /// \return True if the two time deltas are equals; false otherwise.
12108334c51SBrooks Davis bool
operator ==(const datetime::delta & other) const12208334c51SBrooks Davis datetime::delta::operator==(const datetime::delta& other) const
12308334c51SBrooks Davis {
12408334c51SBrooks Davis return seconds == other.seconds && useconds == other.useconds;
12508334c51SBrooks Davis }
12608334c51SBrooks Davis
12708334c51SBrooks Davis
12808334c51SBrooks Davis /// Checks if two time deltas are different.
12908334c51SBrooks Davis ///
13008334c51SBrooks Davis /// \param other The object to compare to.
13108334c51SBrooks Davis ///
13208334c51SBrooks Davis /// \return True if the two time deltas are different; false otherwise.
13308334c51SBrooks Davis bool
operator !=(const datetime::delta & other) const13408334c51SBrooks Davis datetime::delta::operator!=(const datetime::delta& other) const
13508334c51SBrooks Davis {
13608334c51SBrooks Davis return !(*this == other);
13708334c51SBrooks Davis }
13808334c51SBrooks Davis
13908334c51SBrooks Davis
14008334c51SBrooks Davis /// Checks if this time delta is shorter than another one.
14108334c51SBrooks Davis ///
14208334c51SBrooks Davis /// \param other The object to compare to.
14308334c51SBrooks Davis ///
14408334c51SBrooks Davis /// \return True if this time delta is shorter than other; false otherwise.
14508334c51SBrooks Davis bool
operator <(const datetime::delta & other) const14608334c51SBrooks Davis datetime::delta::operator<(const datetime::delta& other) const
14708334c51SBrooks Davis {
14808334c51SBrooks Davis return seconds < other.seconds ||
14908334c51SBrooks Davis (seconds == other.seconds && useconds < other.useconds);
15008334c51SBrooks Davis }
15108334c51SBrooks Davis
15208334c51SBrooks Davis
15308334c51SBrooks Davis /// Checks if this time delta is shorter than or equal to another one.
15408334c51SBrooks Davis ///
15508334c51SBrooks Davis /// \param other The object to compare to.
15608334c51SBrooks Davis ///
15708334c51SBrooks Davis /// \return True if this time delta is shorter than or equal to; false
15808334c51SBrooks Davis /// otherwise.
15908334c51SBrooks Davis bool
operator <=(const datetime::delta & other) const16008334c51SBrooks Davis datetime::delta::operator<=(const datetime::delta& other) const
16108334c51SBrooks Davis {
16208334c51SBrooks Davis return (*this) < other || (*this) == other;
16308334c51SBrooks Davis }
16408334c51SBrooks Davis
16508334c51SBrooks Davis
16608334c51SBrooks Davis /// Checks if this time delta is larger than another one.
16708334c51SBrooks Davis ///
16808334c51SBrooks Davis /// \param other The object to compare to.
16908334c51SBrooks Davis ///
17008334c51SBrooks Davis /// \return True if this time delta is larger than other; false otherwise.
17108334c51SBrooks Davis bool
operator >(const datetime::delta & other) const17208334c51SBrooks Davis datetime::delta::operator>(const datetime::delta& other) const
17308334c51SBrooks Davis {
17408334c51SBrooks Davis return seconds > other.seconds ||
17508334c51SBrooks Davis (seconds == other.seconds && useconds > other.useconds);
17608334c51SBrooks Davis }
17708334c51SBrooks Davis
17808334c51SBrooks Davis
17908334c51SBrooks Davis /// Checks if this time delta is larger than or equal to another one.
18008334c51SBrooks Davis ///
18108334c51SBrooks Davis /// \param other The object to compare to.
18208334c51SBrooks Davis ///
18308334c51SBrooks Davis /// \return True if this time delta is larger than or equal to; false
18408334c51SBrooks Davis /// otherwise.
18508334c51SBrooks Davis bool
operator >=(const datetime::delta & other) const18608334c51SBrooks Davis datetime::delta::operator>=(const datetime::delta& other) const
18708334c51SBrooks Davis {
18808334c51SBrooks Davis return (*this) > other || (*this) == other;
18908334c51SBrooks Davis }
19008334c51SBrooks Davis
19108334c51SBrooks Davis
19208334c51SBrooks Davis /// Adds a time delta to this one.
19308334c51SBrooks Davis ///
19408334c51SBrooks Davis /// \param other The time delta to add.
19508334c51SBrooks Davis ///
19608334c51SBrooks Davis /// \return The addition of this time delta with the other time delta.
19708334c51SBrooks Davis datetime::delta
operator +(const datetime::delta & other) const19808334c51SBrooks Davis datetime::delta::operator+(const datetime::delta& other) const
19908334c51SBrooks Davis {
20008334c51SBrooks Davis return delta::from_microseconds(to_microseconds() +
20108334c51SBrooks Davis other.to_microseconds());
20208334c51SBrooks Davis }
20308334c51SBrooks Davis
20408334c51SBrooks Davis
20508334c51SBrooks Davis /// Adds a time delta to this one and updates this with the result.
20608334c51SBrooks Davis ///
20708334c51SBrooks Davis /// \param other The time delta to add.
20808334c51SBrooks Davis ///
20908334c51SBrooks Davis /// \return The addition of this time delta with the other time delta.
21008334c51SBrooks Davis datetime::delta&
operator +=(const datetime::delta & other)21108334c51SBrooks Davis datetime::delta::operator+=(const datetime::delta& other)
21208334c51SBrooks Davis {
21308334c51SBrooks Davis *this = *this + other;
21408334c51SBrooks Davis return *this;
21508334c51SBrooks Davis }
21608334c51SBrooks Davis
21708334c51SBrooks Davis
21808334c51SBrooks Davis /// Scales this delta by a positive integral factor.
21908334c51SBrooks Davis ///
22008334c51SBrooks Davis /// \param factor The scaling factor.
22108334c51SBrooks Davis ///
22208334c51SBrooks Davis /// \return The scaled delta.
22308334c51SBrooks Davis datetime::delta
operator *(const std::size_t factor) const22408334c51SBrooks Davis datetime::delta::operator*(const std::size_t factor) const
22508334c51SBrooks Davis {
22608334c51SBrooks Davis return delta::from_microseconds(to_microseconds() * factor);
22708334c51SBrooks Davis }
22808334c51SBrooks Davis
22908334c51SBrooks Davis
23008334c51SBrooks Davis /// Scales this delta by and updates this delta with the result.
23108334c51SBrooks Davis ///
23208334c51SBrooks Davis /// \param factor The scaling factor.
23308334c51SBrooks Davis ///
23408334c51SBrooks Davis /// \return The scaled delta as a reference to the input object.
23508334c51SBrooks Davis datetime::delta&
operator *=(const std::size_t factor)23608334c51SBrooks Davis datetime::delta::operator*=(const std::size_t factor)
23708334c51SBrooks Davis {
23808334c51SBrooks Davis *this = *this * factor;
23908334c51SBrooks Davis return *this;
24008334c51SBrooks Davis }
24108334c51SBrooks Davis
24208334c51SBrooks Davis
24308334c51SBrooks Davis /// Injects the object into a stream.
24408334c51SBrooks Davis ///
24508334c51SBrooks Davis /// \param output The stream into which to inject the object.
24608334c51SBrooks Davis /// \param object The object to format.
24708334c51SBrooks Davis ///
24808334c51SBrooks Davis /// \return The output stream.
24908334c51SBrooks Davis std::ostream&
operator <<(std::ostream & output,const delta & object)25008334c51SBrooks Davis datetime::operator<<(std::ostream& output, const delta& object)
25108334c51SBrooks Davis {
25208334c51SBrooks Davis return (output << object.to_microseconds() << "us");
25308334c51SBrooks Davis }
25408334c51SBrooks Davis
25508334c51SBrooks Davis
25608334c51SBrooks Davis namespace utils {
25708334c51SBrooks Davis namespace datetime {
25808334c51SBrooks Davis
25908334c51SBrooks Davis
26008334c51SBrooks Davis /// Internal representation for datetime::timestamp.
26108334c51SBrooks Davis struct timestamp::impl : utils::noncopyable {
26208334c51SBrooks Davis /// The raw timestamp as provided by libc.
26308334c51SBrooks Davis ::timeval data;
26408334c51SBrooks Davis
26508334c51SBrooks Davis /// Constructs an impl object from initialized data.
26608334c51SBrooks Davis ///
26708334c51SBrooks Davis /// \param data_ The raw timestamp to use.
implutils::datetime::timestamp::impl26808334c51SBrooks Davis impl(const ::timeval& data_) : data(data_)
26908334c51SBrooks Davis {
27008334c51SBrooks Davis }
27108334c51SBrooks Davis };
27208334c51SBrooks Davis
27308334c51SBrooks Davis
27408334c51SBrooks Davis } // namespace datetime
27508334c51SBrooks Davis } // namespace utils
27608334c51SBrooks Davis
27708334c51SBrooks Davis
27808334c51SBrooks Davis /// Constructs a new timestamp.
27908334c51SBrooks Davis ///
28008334c51SBrooks Davis /// \param pimpl_ An existing impl representation.
timestamp(std::shared_ptr<impl> pimpl_)28108334c51SBrooks Davis datetime::timestamp::timestamp(std::shared_ptr< impl > pimpl_) :
28208334c51SBrooks Davis _pimpl(pimpl_)
28308334c51SBrooks Davis {
28408334c51SBrooks Davis }
28508334c51SBrooks Davis
28608334c51SBrooks Davis
28708334c51SBrooks Davis /// Constructs a timestamp from the amount of microseconds since the epoch.
28808334c51SBrooks Davis ///
28908334c51SBrooks Davis /// \param value Microseconds since the epoch in UTC. Must be positive.
29008334c51SBrooks Davis ///
29108334c51SBrooks Davis /// \return A new timestamp.
29208334c51SBrooks Davis datetime::timestamp
from_microseconds(const int64_t value)29308334c51SBrooks Davis datetime::timestamp::from_microseconds(const int64_t value)
29408334c51SBrooks Davis {
29508334c51SBrooks Davis PRE(value >= 0);
29608334c51SBrooks Davis ::timeval data;
29708334c51SBrooks Davis data.tv_sec = static_cast< time_t >(value / 1000000);
29808334c51SBrooks Davis data.tv_usec = static_cast< suseconds_t >(value % 1000000);
29908334c51SBrooks Davis return timestamp(std::shared_ptr< impl >(new impl(data)));
30008334c51SBrooks Davis }
30108334c51SBrooks Davis
30208334c51SBrooks Davis
30308334c51SBrooks Davis /// Constructs a timestamp based on user-friendly values.
30408334c51SBrooks Davis ///
30508334c51SBrooks Davis /// \param year The year in the [1900,inf) range.
30608334c51SBrooks Davis /// \param month The month in the [1,12] range.
30708334c51SBrooks Davis /// \param day The day in the [1,30] range.
30808334c51SBrooks Davis /// \param hour The hour in the [0,23] range.
30908334c51SBrooks Davis /// \param minute The minute in the [0,59] range.
31008334c51SBrooks Davis /// \param second The second in the [0,60] range. Yes, that is 60, which can be
31108334c51SBrooks Davis /// the case on leap seconds.
31208334c51SBrooks Davis /// \param microsecond The microsecond in the [0,999999] range.
31308334c51SBrooks Davis ///
31408334c51SBrooks Davis /// \return A new timestamp.
31508334c51SBrooks Davis 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)31608334c51SBrooks Davis datetime::timestamp::from_values(const int year, const int month,
31708334c51SBrooks Davis const int day, const int hour,
31808334c51SBrooks Davis const int minute, const int second,
31908334c51SBrooks Davis const int microsecond)
32008334c51SBrooks Davis {
32108334c51SBrooks Davis PRE(year >= 1900);
32208334c51SBrooks Davis PRE(month >= 1 && month <= 12);
32308334c51SBrooks Davis PRE(day >= 1 && day <= 30);
32408334c51SBrooks Davis PRE(hour >= 0 && hour <= 23);
32508334c51SBrooks Davis PRE(minute >= 0 && minute <= 59);
32608334c51SBrooks Davis PRE(second >= 0 && second <= 60);
32708334c51SBrooks Davis PRE(microsecond >= 0 && microsecond <= 999999);
32808334c51SBrooks Davis
32908334c51SBrooks Davis // The code below is quite convoluted. The problem is that we can't assume
33008334c51SBrooks Davis // that some fields (like tm_zone) of ::tm exist, and thus we can't blindly
33108334c51SBrooks Davis // set them from the code. Instead of detecting their presence in the
33208334c51SBrooks Davis // configure script, we just query the current time to initialize such
33308334c51SBrooks Davis // fields and then we override the ones we are interested in. (There might
33408334c51SBrooks Davis // be some better way to do this, but I don't know it and the documentation
33508334c51SBrooks Davis // does not shed much light into how to create your own fake date.)
33608334c51SBrooks Davis
33708334c51SBrooks Davis const time_t current_time = ::time(NULL);
33808334c51SBrooks Davis
33908334c51SBrooks Davis ::tm timedata;
34008334c51SBrooks Davis if (::gmtime_r(¤t_time, &timedata) == NULL)
34108334c51SBrooks Davis UNREACHABLE;
34208334c51SBrooks Davis
34308334c51SBrooks Davis timedata.tm_sec = second;
34408334c51SBrooks Davis timedata.tm_min = minute;
34508334c51SBrooks Davis timedata.tm_hour = hour;
34608334c51SBrooks Davis timedata.tm_mday = day;
34708334c51SBrooks Davis timedata.tm_mon = month - 1;
34808334c51SBrooks Davis timedata.tm_year = year - 1900;
34908334c51SBrooks Davis // Ignored: timedata.tm_wday
35008334c51SBrooks Davis // Ignored: timedata.tm_yday
35108334c51SBrooks Davis
35208334c51SBrooks Davis ::timeval data;
35308334c51SBrooks Davis data.tv_sec = ::mktime(&timedata);
35408334c51SBrooks Davis data.tv_usec = static_cast< suseconds_t >(microsecond);
35508334c51SBrooks Davis return timestamp(std::shared_ptr< impl >(new impl(data)));
35608334c51SBrooks Davis }
35708334c51SBrooks Davis
35808334c51SBrooks Davis
35908334c51SBrooks Davis /// Constructs a new timestamp representing the current time in UTC.
36008334c51SBrooks Davis ///
36108334c51SBrooks Davis /// \return A new timestamp.
36208334c51SBrooks Davis datetime::timestamp
now(void)36308334c51SBrooks Davis datetime::timestamp::now(void)
36408334c51SBrooks Davis {
36508334c51SBrooks Davis if (mock_now)
36608334c51SBrooks Davis return mock_now.get();
36708334c51SBrooks Davis
36808334c51SBrooks Davis ::timeval data;
36908334c51SBrooks Davis {
37008334c51SBrooks Davis const int ret = ::gettimeofday(&data, NULL);
37108334c51SBrooks Davis INV(ret != -1);
37208334c51SBrooks Davis }
37308334c51SBrooks Davis
37408334c51SBrooks Davis return timestamp(std::shared_ptr< impl >(new impl(data)));
37508334c51SBrooks Davis }
37608334c51SBrooks Davis
37708334c51SBrooks Davis
37808334c51SBrooks Davis /// Formats a timestamp.
37908334c51SBrooks Davis ///
38008334c51SBrooks Davis /// \param format The format string to use as consumed by strftime(3).
38108334c51SBrooks Davis ///
38208334c51SBrooks Davis /// \return The formatted time.
38308334c51SBrooks Davis std::string
strftime(const std::string & format) const38408334c51SBrooks Davis datetime::timestamp::strftime(const std::string& format) const
38508334c51SBrooks Davis {
38608334c51SBrooks Davis ::tm timedata;
38708334c51SBrooks Davis // This conversion to time_t is necessary because tv_sec is not guaranteed
38808334c51SBrooks Davis // to be a time_t. For example, it isn't in NetBSD 5.x
38908334c51SBrooks Davis ::time_t epoch_seconds;
39008334c51SBrooks Davis epoch_seconds = _pimpl->data.tv_sec;
39108334c51SBrooks Davis if (::gmtime_r(&epoch_seconds, &timedata) == NULL)
39208334c51SBrooks Davis UNREACHABLE_MSG("gmtime_r(3) did not accept the value returned by "
39308334c51SBrooks Davis "gettimeofday(2)");
39408334c51SBrooks Davis
39508334c51SBrooks Davis char buf[128];
39608334c51SBrooks Davis if (::strftime(buf, sizeof(buf), format.c_str(), &timedata) == 0)
39708334c51SBrooks Davis UNREACHABLE_MSG("Arbitrary-long format strings are unimplemented");
39808334c51SBrooks Davis return buf;
39908334c51SBrooks Davis }
40008334c51SBrooks Davis
40108334c51SBrooks Davis
40208334c51SBrooks Davis /// Formats a timestamp with the ISO 8601 standard and in UTC.
40308334c51SBrooks Davis ///
40408334c51SBrooks Davis /// \return A string with the formatted timestamp.
40508334c51SBrooks Davis std::string
to_iso8601_in_utc(void) const40608334c51SBrooks Davis datetime::timestamp::to_iso8601_in_utc(void) const
40708334c51SBrooks Davis {
40808334c51SBrooks Davis return F("%s.%06sZ") % strftime("%Y-%m-%dT%H:%M:%S") % _pimpl->data.tv_usec;
40908334c51SBrooks Davis }
41008334c51SBrooks Davis
41108334c51SBrooks Davis
41208334c51SBrooks Davis /// Returns the number of microseconds since the epoch in UTC.
41308334c51SBrooks Davis ///
41408334c51SBrooks Davis /// \return A number of microseconds.
41508334c51SBrooks Davis int64_t
to_microseconds(void) const41608334c51SBrooks Davis datetime::timestamp::to_microseconds(void) const
41708334c51SBrooks Davis {
41808334c51SBrooks Davis return static_cast< int64_t >(_pimpl->data.tv_sec) * 1000000 +
41908334c51SBrooks Davis _pimpl->data.tv_usec;
42008334c51SBrooks Davis }
42108334c51SBrooks Davis
42208334c51SBrooks Davis
42308334c51SBrooks Davis /// Returns the number of seconds since the epoch in UTC.
42408334c51SBrooks Davis ///
42508334c51SBrooks Davis /// \return A number of seconds.
42608334c51SBrooks Davis int64_t
to_seconds(void) const42708334c51SBrooks Davis datetime::timestamp::to_seconds(void) const
42808334c51SBrooks Davis {
42908334c51SBrooks Davis return static_cast< int64_t >(_pimpl->data.tv_sec);
43008334c51SBrooks Davis }
43108334c51SBrooks Davis
43208334c51SBrooks Davis
43308334c51SBrooks Davis /// Sets the current time for testing purposes.
43408334c51SBrooks Davis 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)43508334c51SBrooks Davis datetime::set_mock_now(const int year, const int month,
43608334c51SBrooks Davis const int day, const int hour,
43708334c51SBrooks Davis const int minute, const int second,
43808334c51SBrooks Davis const int microsecond)
43908334c51SBrooks Davis {
44008334c51SBrooks Davis mock_now = timestamp::from_values(year, month, day, hour, minute, second,
44108334c51SBrooks Davis microsecond);
44208334c51SBrooks Davis }
44308334c51SBrooks Davis
44408334c51SBrooks Davis
44508334c51SBrooks Davis /// Sets the current time for testing purposes.
44608334c51SBrooks Davis ///
44708334c51SBrooks Davis /// \param mock_now_ The mock timestamp to set the time to.
44808334c51SBrooks Davis void
set_mock_now(const timestamp & mock_now_)44908334c51SBrooks Davis datetime::set_mock_now(const timestamp& mock_now_)
45008334c51SBrooks Davis {
45108334c51SBrooks Davis mock_now = mock_now_;
45208334c51SBrooks Davis }
45308334c51SBrooks Davis
45408334c51SBrooks Davis
45508334c51SBrooks Davis /// Checks if two timestamps are equal.
45608334c51SBrooks Davis ///
45708334c51SBrooks Davis /// \param other The object to compare to.
45808334c51SBrooks Davis ///
45908334c51SBrooks Davis /// \return True if the two timestamps are equals; false otherwise.
46008334c51SBrooks Davis bool
operator ==(const datetime::timestamp & other) const46108334c51SBrooks Davis datetime::timestamp::operator==(const datetime::timestamp& other) const
46208334c51SBrooks Davis {
46308334c51SBrooks Davis return _pimpl->data.tv_sec == other._pimpl->data.tv_sec &&
46408334c51SBrooks Davis _pimpl->data.tv_usec == other._pimpl->data.tv_usec;
46508334c51SBrooks Davis }
46608334c51SBrooks Davis
46708334c51SBrooks Davis
46808334c51SBrooks Davis /// Checks if two timestamps are different.
46908334c51SBrooks Davis ///
47008334c51SBrooks Davis /// \param other The object to compare to.
47108334c51SBrooks Davis ///
47208334c51SBrooks Davis /// \return True if the two timestamps are different; false otherwise.
47308334c51SBrooks Davis bool
operator !=(const datetime::timestamp & other) const47408334c51SBrooks Davis datetime::timestamp::operator!=(const datetime::timestamp& other) const
47508334c51SBrooks Davis {
47608334c51SBrooks Davis return !(*this == other);
47708334c51SBrooks Davis }
47808334c51SBrooks Davis
47908334c51SBrooks Davis
48008334c51SBrooks Davis /// Checks if a timestamp is before another.
48108334c51SBrooks Davis ///
48208334c51SBrooks Davis /// \param other The object to compare to.
48308334c51SBrooks Davis ///
48408334c51SBrooks Davis /// \return True if this timestamp comes before other; false otherwise.
48508334c51SBrooks Davis bool
operator <(const datetime::timestamp & other) const48608334c51SBrooks Davis datetime::timestamp::operator<(const datetime::timestamp& other) const
48708334c51SBrooks Davis {
48808334c51SBrooks Davis return to_microseconds() < other.to_microseconds();
48908334c51SBrooks Davis }
49008334c51SBrooks Davis
49108334c51SBrooks Davis
49208334c51SBrooks Davis /// Checks if a timestamp is before or equal to another.
49308334c51SBrooks Davis ///
49408334c51SBrooks Davis /// \param other The object to compare to.
49508334c51SBrooks Davis ///
49608334c51SBrooks Davis /// \return True if this timestamp comes before other or is equal to it;
49708334c51SBrooks Davis /// false otherwise.
49808334c51SBrooks Davis bool
operator <=(const datetime::timestamp & other) const49908334c51SBrooks Davis datetime::timestamp::operator<=(const datetime::timestamp& other) const
50008334c51SBrooks Davis {
50108334c51SBrooks Davis return to_microseconds() <= other.to_microseconds();
50208334c51SBrooks Davis }
50308334c51SBrooks Davis
50408334c51SBrooks Davis
50508334c51SBrooks Davis /// Checks if a timestamp is after another.
50608334c51SBrooks Davis ///
50708334c51SBrooks Davis /// \param other The object to compare to.
50808334c51SBrooks Davis ///
50908334c51SBrooks Davis /// \return True if this timestamp comes after other; false otherwise;
51008334c51SBrooks Davis bool
operator >(const datetime::timestamp & other) const51108334c51SBrooks Davis datetime::timestamp::operator>(const datetime::timestamp& other) const
51208334c51SBrooks Davis {
51308334c51SBrooks Davis return to_microseconds() > other.to_microseconds();
51408334c51SBrooks Davis }
51508334c51SBrooks Davis
51608334c51SBrooks Davis
51708334c51SBrooks Davis /// Checks if a timestamp is after or equal to another.
51808334c51SBrooks Davis ///
51908334c51SBrooks Davis /// \param other The object to compare to.
52008334c51SBrooks Davis ///
52108334c51SBrooks Davis /// \return True if this timestamp comes after other or is equal to it;
52208334c51SBrooks Davis /// false otherwise.
52308334c51SBrooks Davis bool
operator >=(const datetime::timestamp & other) const52408334c51SBrooks Davis datetime::timestamp::operator>=(const datetime::timestamp& other) const
52508334c51SBrooks Davis {
52608334c51SBrooks Davis return to_microseconds() >= other.to_microseconds();
52708334c51SBrooks Davis }
52808334c51SBrooks Davis
52908334c51SBrooks Davis
53008334c51SBrooks Davis /// Calculates the addition of a delta to a timestamp.
53108334c51SBrooks Davis ///
53208334c51SBrooks Davis /// \param other The delta to add.
53308334c51SBrooks Davis ///
53408334c51SBrooks Davis /// \return A new timestamp in the future.
53508334c51SBrooks Davis datetime::timestamp
operator +(const datetime::delta & other) const53608334c51SBrooks Davis datetime::timestamp::operator+(const datetime::delta& other) const
53708334c51SBrooks Davis {
53808334c51SBrooks Davis return datetime::timestamp::from_microseconds(to_microseconds() +
53908334c51SBrooks Davis other.to_microseconds());
54008334c51SBrooks Davis }
54108334c51SBrooks Davis
54208334c51SBrooks Davis
54308334c51SBrooks Davis /// Calculates the addition of a delta to this timestamp.
54408334c51SBrooks Davis ///
54508334c51SBrooks Davis /// \param other The delta to add.
54608334c51SBrooks Davis ///
54708334c51SBrooks Davis /// \return A reference to the modified timestamp.
54808334c51SBrooks Davis datetime::timestamp&
operator +=(const datetime::delta & other)54908334c51SBrooks Davis datetime::timestamp::operator+=(const datetime::delta& other)
55008334c51SBrooks Davis {
55108334c51SBrooks Davis *this = *this + other;
55208334c51SBrooks Davis return *this;
55308334c51SBrooks Davis }
55408334c51SBrooks Davis
55508334c51SBrooks Davis
55608334c51SBrooks Davis /// Calculates the subtraction of a delta from a timestamp.
55708334c51SBrooks Davis ///
55808334c51SBrooks Davis /// \param other The delta to subtract.
55908334c51SBrooks Davis ///
56008334c51SBrooks Davis /// \return A new timestamp in the past.
56108334c51SBrooks Davis datetime::timestamp
operator -(const datetime::delta & other) const56208334c51SBrooks Davis datetime::timestamp::operator-(const datetime::delta& other) const
56308334c51SBrooks Davis {
56408334c51SBrooks Davis return datetime::timestamp::from_microseconds(to_microseconds() -
56508334c51SBrooks Davis other.to_microseconds());
56608334c51SBrooks Davis }
56708334c51SBrooks Davis
56808334c51SBrooks Davis
56908334c51SBrooks Davis /// Calculates the subtraction of a delta from this timestamp.
57008334c51SBrooks Davis ///
57108334c51SBrooks Davis /// \param other The delta to subtract.
57208334c51SBrooks Davis ///
57308334c51SBrooks Davis /// \return A reference to the modified timestamp.
57408334c51SBrooks Davis datetime::timestamp&
operator -=(const datetime::delta & other)57508334c51SBrooks Davis datetime::timestamp::operator-=(const datetime::delta& other)
57608334c51SBrooks Davis {
57708334c51SBrooks Davis *this = *this - other;
57808334c51SBrooks Davis return *this;
57908334c51SBrooks Davis }
58008334c51SBrooks Davis
58108334c51SBrooks Davis
58208334c51SBrooks Davis /// Calculates the delta between two timestamps.
58308334c51SBrooks Davis ///
58408334c51SBrooks Davis /// \param other The subtrahend.
58508334c51SBrooks Davis ///
58608334c51SBrooks Davis /// \return The difference between this object and the other object.
58708334c51SBrooks Davis ///
58808334c51SBrooks Davis /// \throw std::runtime_error If the subtraction would result in a negative time
58908334c51SBrooks Davis /// delta, which are currently not supported.
59008334c51SBrooks Davis datetime::delta
operator -(const datetime::timestamp & other) const59108334c51SBrooks Davis datetime::timestamp::operator-(const datetime::timestamp& other) const
59208334c51SBrooks Davis {
593d0738729SEnji Cooper /*
594d0738729SEnji Cooper * XXX-BD: gettimeofday isn't necessarily monotonic so return the
595d0738729SEnji Cooper * smallest non-zero delta if time went backwards.
596d0738729SEnji Cooper */
597d0738729SEnji Cooper if ((*this) < other)
598d0738729SEnji Cooper return datetime::delta::from_microseconds(1);
59908334c51SBrooks Davis return datetime::delta::from_microseconds(to_microseconds() -
60008334c51SBrooks Davis other.to_microseconds());
60108334c51SBrooks Davis }
60208334c51SBrooks Davis
60308334c51SBrooks Davis
60408334c51SBrooks Davis /// Injects the object into a stream.
60508334c51SBrooks Davis ///
60608334c51SBrooks Davis /// \param output The stream into which to inject the object.
60708334c51SBrooks Davis /// \param object The object to format.
60808334c51SBrooks Davis ///
60908334c51SBrooks Davis /// \return The output stream.
61008334c51SBrooks Davis std::ostream&
operator <<(std::ostream & output,const timestamp & object)61108334c51SBrooks Davis datetime::operator<<(std::ostream& output, const timestamp& object)
61208334c51SBrooks Davis {
61308334c51SBrooks Davis return (output << object.to_microseconds() << "us");
61408334c51SBrooks Davis }
615