1 // Copyright 2010 Google Inc. 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 "utils/optional.ipp" 38 #include "utils/sanity.hpp" 39 40 namespace datetime = utils::datetime; 41 42 using utils::none; 43 using utils::optional; 44 45 46 namespace { 47 48 49 /// Fake value for the current time. 50 static optional< datetime::timestamp > mock_now = none; 51 52 53 } // anonymous namespace 54 55 56 /// Creates a zero time delta. 57 datetime::delta::delta(void) : 58 seconds(0), 59 useconds(0) 60 { 61 } 62 63 64 /// Creates a time delta. 65 /// 66 /// \param seconds_ The seconds in the delta. 67 /// \param useconds_ The microseconds in the delta. 68 datetime::delta::delta(const int64_t seconds_, 69 const unsigned long useconds_) : 70 seconds(seconds_), 71 useconds(useconds_) 72 { 73 } 74 75 76 /// Converts a time expressed in microseconds to a delta. 77 /// 78 /// \param useconds The amount of microseconds representing the delta. 79 /// 80 /// \return A new delta object. 81 datetime::delta 82 datetime::delta::from_microseconds(const int64_t useconds) 83 { 84 return delta(useconds / 1000000, useconds % 1000000); 85 } 86 87 88 /// Convers the delta to a flat representation expressed in microseconds. 89 /// 90 /// \return The amount of microseconds that corresponds to this delta. 91 int64_t 92 datetime::delta::to_microseconds(void) const 93 { 94 return seconds * 1000000 + useconds; 95 } 96 97 98 /// Checks if two time deltas are equal. 99 /// 100 /// \param other The object to compare to. 101 /// 102 /// \return True if the two time deltas are equals; false otherwise. 103 bool 104 datetime::delta::operator==(const datetime::delta& other) const 105 { 106 return seconds == other.seconds && useconds == other.useconds; 107 } 108 109 110 /// Checks if two time deltas are different. 111 /// 112 /// \param other The object to compare to. 113 /// 114 /// \return True if the two time deltas are different; false otherwise. 115 bool 116 datetime::delta::operator!=(const datetime::delta& other) const 117 { 118 return !(*this == other); 119 } 120 121 122 /// Adds a time delta to this one. 123 /// 124 /// \param other The time delta to add. 125 /// 126 /// \return The addition of this time delta with the other time delta. 127 datetime::delta 128 datetime::delta::operator+(const datetime::delta& other) const 129 { 130 return delta::from_microseconds(to_microseconds() + 131 other.to_microseconds()); 132 } 133 134 135 /// Adds a time delta to this one and updates this with the result. 136 /// 137 /// \param other The time delta to add. 138 /// 139 /// \return The addition of this time delta with the other time delta. 140 datetime::delta 141 datetime::delta::operator+=(const datetime::delta& other) 142 { 143 *this = *this + other; 144 return *this; 145 } 146 147 148 /// Injects the object into a stream. 149 /// 150 /// \param output The stream into which to inject the object. 151 /// \param object The object to format. 152 /// 153 /// \return The output stream. 154 std::ostream& 155 datetime::operator<<(std::ostream& output, const delta& object) 156 { 157 return (output << object.to_microseconds() << "us"); 158 } 159 160 161 namespace utils { 162 namespace datetime { 163 164 165 /// Internal representation for datetime::timestamp. 166 struct timestamp::impl { 167 /// The raw timestamp as provided by libc. 168 ::timeval data; 169 170 /// Constructs an impl object from initialized data. 171 /// 172 /// \param data_ The raw timestamp to use. 173 impl(const ::timeval& data_) : data(data_) 174 { 175 } 176 }; 177 178 179 } // namespace datetime 180 } // namespace utils 181 182 183 /// Constructs a new timestamp. 184 /// 185 /// \param pimpl_ An existing impl representation. 186 datetime::timestamp::timestamp(std::shared_ptr< impl > pimpl_) : 187 _pimpl(pimpl_) 188 { 189 } 190 191 192 /// Constructs a timestamp from the amount of microseconds since the epoch. 193 /// 194 /// \param value Microseconds since the epoch in UTC. Must be positive. 195 /// 196 /// \return A new timestamp. 197 datetime::timestamp 198 datetime::timestamp::from_microseconds(const int64_t value) 199 { 200 PRE(value >= 0); 201 ::timeval data; 202 data.tv_sec = static_cast< time_t >(value / 1000000); 203 data.tv_usec = static_cast< suseconds_t >(value % 1000000); 204 return timestamp(std::shared_ptr< impl >(new impl(data))); 205 } 206 207 208 /// Constructs a timestamp based on user-friendly values. 209 /// 210 /// \param year The year in the [1900,inf) range. 211 /// \param month The month in the [1,12] range. 212 /// \param day The day in the [1,30] range. 213 /// \param hour The hour in the [0,23] range. 214 /// \param minute The minute in the [0,59] range. 215 /// \param second The second in the [0,60] range. Yes, that is 60, which can be 216 /// the case on leap seconds. 217 /// \param microsecond The microsecond in the [0,999999] range. 218 /// 219 /// \return A new timestamp. 220 datetime::timestamp 221 datetime::timestamp::from_values(const int year, const int month, 222 const int day, const int hour, 223 const int minute, const int second, 224 const int microsecond) 225 { 226 PRE(year >= 1900); 227 PRE(month >= 1 && month <= 12); 228 PRE(day >= 1 && day <= 30); 229 PRE(hour >= 0 && hour <= 23); 230 PRE(minute >= 0 && minute <= 59); 231 PRE(second >= 0 && second <= 60); 232 PRE(microsecond >= 0 && microsecond <= 999999); 233 234 // The code below is quite convoluted. The problem is that we can't assume 235 // that some fields (like tm_zone) of ::tm exist, and thus we can't blindly 236 // set them from the code. Instead of detecting their presence in the 237 // configure script, we just query the current time to initialize such 238 // fields and then we override the ones we are interested in. (There might 239 // be some better way to do this, but I don't know it and the documentation 240 // does not shed much light into how to create your own fake date.) 241 242 const time_t current_time = ::time(NULL); 243 244 ::tm timedata; 245 if (::gmtime_r(¤t_time, &timedata) == NULL) 246 UNREACHABLE; 247 248 timedata.tm_sec = second; 249 timedata.tm_min = minute; 250 timedata.tm_hour = hour; 251 timedata.tm_mday = day; 252 timedata.tm_mon = month - 1; 253 timedata.tm_year = year - 1900; 254 // Ignored: timedata.tm_wday 255 // Ignored: timedata.tm_yday 256 257 ::timeval data; 258 data.tv_sec = ::mktime(&timedata); 259 data.tv_usec = static_cast< suseconds_t >(microsecond); 260 return timestamp(std::shared_ptr< impl >(new impl(data))); 261 } 262 263 264 /// Constructs a new timestamp representing the current time in UTC. 265 /// 266 /// \return A new timestamp. 267 datetime::timestamp 268 datetime::timestamp::now(void) 269 { 270 if (mock_now) 271 return mock_now.get(); 272 273 ::timeval data; 274 { 275 const int ret = ::gettimeofday(&data, NULL); 276 INV(ret != -1); 277 } 278 279 return timestamp(std::shared_ptr< impl >(new impl(data))); 280 } 281 282 283 /// Formats a timestamp. 284 /// 285 /// \param format The format string to use as consumed by strftime(3). 286 /// 287 /// \return The formatted time. 288 std::string 289 datetime::timestamp::strftime(const std::string& format) const 290 { 291 ::tm timedata; 292 // This conversion to time_t is necessary because tv_sec is not guaranteed 293 // to be a time_t. For example, it isn't in NetBSD 5.x 294 ::time_t epoch_seconds; 295 epoch_seconds = _pimpl->data.tv_sec; 296 if (::gmtime_r(&epoch_seconds, &timedata) == NULL) 297 UNREACHABLE_MSG("gmtime_r(3) did not accept the value returned by " 298 "gettimeofday(2)"); 299 300 char buf[128]; 301 if (::strftime(buf, sizeof(buf), format.c_str(), &timedata) == 0) 302 UNREACHABLE_MSG("Arbitrary-long format strings are unimplemented"); 303 return buf; 304 } 305 306 307 /// Returns the number of microseconds since the epoch in UTC. 308 /// 309 /// \return A number of microseconds. 310 int64_t 311 datetime::timestamp::to_microseconds(void) const 312 { 313 return static_cast< int64_t >(_pimpl->data.tv_sec) * 1000000 + 314 _pimpl->data.tv_usec; 315 } 316 317 318 /// Returns the number of seconds since the epoch in UTC. 319 /// 320 /// \return A number of seconds. 321 int64_t 322 datetime::timestamp::to_seconds(void) const 323 { 324 return static_cast< int64_t >(_pimpl->data.tv_sec); 325 } 326 327 328 /// Sets the current time for testing purposes. 329 void 330 datetime::set_mock_now(const int year, const int month, 331 const int day, const int hour, 332 const int minute, const int second, 333 const int microsecond) 334 { 335 mock_now = timestamp::from_values(year, month, day, hour, minute, second, 336 microsecond); 337 } 338 339 340 /// Checks if two timestamps are equal. 341 /// 342 /// \param other The object to compare to. 343 /// 344 /// \return True if the two timestamps are equals; false otherwise. 345 bool 346 datetime::timestamp::operator==(const datetime::timestamp& other) const 347 { 348 return _pimpl->data.tv_sec == other._pimpl->data.tv_sec && 349 _pimpl->data.tv_usec == other._pimpl->data.tv_usec; 350 } 351 352 353 /// Checks if two timestamps are different. 354 /// 355 /// \param other The object to compare to. 356 /// 357 /// \return True if the two timestamps are different; false otherwise. 358 bool 359 datetime::timestamp::operator!=(const datetime::timestamp& other) const 360 { 361 return !(*this == other); 362 } 363 364 365 /// Calculates the delta between two timestamps. 366 /// 367 /// \param other The subtrahend. 368 /// 369 /// \return The difference between this object and the other object. 370 datetime::delta 371 datetime::timestamp::operator-(const datetime::timestamp& other) const 372 { 373 return datetime::delta::from_microseconds(to_microseconds() - 374 other.to_microseconds()); 375 } 376 377 378 /// Injects the object into a stream. 379 /// 380 /// \param output The stream into which to inject the object. 381 /// \param object The object to format. 382 /// 383 /// \return The output stream. 384 std::ostream& 385 datetime::operator<<(std::ostream& output, const timestamp& object) 386 { 387 return (output << object.to_microseconds() << "us"); 388 } 389