time.cpp raw

   1  // Copyright (c) 2009-2010 Satoshi Nakamoto
   2  // Copyright (c) 2009-present The Limenka developers
   3  // Distributed under the MIT software license, see the accompanying
   4  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   5  
   6  #include <util/time.h>
   7  
   8  #include <compat/compat.h>
   9  #include <tinyformat.h>
  10  #include <util/check.h>
  11  #include <util/strencodings.h>
  12  
  13  #include <atomic>
  14  #include <chrono>
  15  #include <optional>
  16  #include <string>
  17  #include <string_view>
  18  #include <thread>
  19  
  20  #ifdef WIN32
  21  #include <windows.h>
  22  #include <winnt.h>
  23  
  24  #include <processthreadsapi.h>
  25  #else
  26  #include <ctime>
  27  #endif
  28  
  29  
  30  void UninterruptibleSleep(const std::chrono::microseconds& n) { std::this_thread::sleep_for(n); }
  31  
  32  static std::atomic<std::chrono::seconds> g_mock_time{}; //!< For testing
  33  std::atomic<bool> g_used_system_time{false};
  34  static std::atomic<std::chrono::milliseconds> g_mock_steady_time{}; //!< For testing
  35  
  36  NodeClock::time_point NodeClock::now() noexcept
  37  {
  38      const auto mocktime{g_mock_time.load(std::memory_order_relaxed)};
  39      if (!mocktime.count()) {
  40          g_used_system_time = true;
  41      }
  42      const auto ret{
  43          mocktime.count() ?
  44              mocktime :
  45              std::chrono::system_clock::now().time_since_epoch()};
  46      assert(ret > 0s);
  47      return time_point{ret};
  48  };
  49  
  50  void SetMockTime(int64_t nMockTimeIn) { SetMockTime(std::chrono::seconds{nMockTimeIn}); }
  51  void SetMockTime(std::chrono::seconds mock_time_in)
  52  {
  53      Assert(mock_time_in >= 0s);
  54      g_mock_time.store(mock_time_in, std::memory_order_relaxed);
  55  }
  56  
  57  std::chrono::seconds GetMockTime()
  58  {
  59      return g_mock_time.load(std::memory_order_relaxed);
  60  }
  61  
  62  MockableSteadyClock::time_point MockableSteadyClock::now() noexcept
  63  {
  64      const auto mocktime{g_mock_steady_time.load(std::memory_order_relaxed)};
  65      if (!mocktime.count()) {
  66          g_used_system_time = true;
  67      }
  68      const auto ret{
  69          mocktime.count() ?
  70              mocktime :
  71              std::chrono::steady_clock::now().time_since_epoch()};
  72      return time_point{ret};
  73  };
  74  
  75  void MockableSteadyClock::SetMockTime(std::chrono::milliseconds mock_time_in)
  76  {
  77      Assert(mock_time_in >= 0s);
  78      g_mock_steady_time.store(mock_time_in, std::memory_order_relaxed);
  79  }
  80  
  81  void MockableSteadyClock::ClearMockTime()
  82  {
  83      g_mock_steady_time.store(0ms, std::memory_order_relaxed);
  84  }
  85  
  86  int64_t GetTime() { return GetTime<std::chrono::seconds>().count(); }
  87  
  88  std::string FormatISO8601DateTime(int64_t nTime)
  89  {
  90      const std::chrono::sys_seconds secs{std::chrono::seconds{nTime}};
  91      const auto days{std::chrono::floor<std::chrono::days>(secs)};
  92      const std::chrono::year_month_day ymd{days};
  93      const std::chrono::hh_mm_ss hms{secs - days};
  94      return strprintf("%04i-%02u-%02uT%02i:%02i:%02iZ", signed{ymd.year()}, unsigned{ymd.month()}, unsigned{ymd.day()}, hms.hours().count(), hms.minutes().count(), hms.seconds().count());
  95  }
  96  
  97  std::string FormatISO8601Date(int64_t nTime)
  98  {
  99      const std::chrono::sys_seconds secs{std::chrono::seconds{nTime}};
 100      const auto days{std::chrono::floor<std::chrono::days>(secs)};
 101      const std::chrono::year_month_day ymd{days};
 102      return strprintf("%04i-%02u-%02u", signed{ymd.year()}, unsigned{ymd.month()}, unsigned{ymd.day()});
 103  }
 104  
 105  std::optional<int64_t> ParseISO8601DateTime(std::string_view str)
 106  {
 107      constexpr auto FMT_SIZE{std::string_view{"2000-01-01T01:01:01Z"}.size()};
 108      if (str.size() != FMT_SIZE || str[4] != '-' || str[7] != '-' || str[10] != 'T' || str[13] != ':' || str[16] != ':' || str[19] != 'Z') {
 109          return {};
 110      }
 111      const auto year{ToIntegral<uint16_t>(str.substr(0, 4))};
 112      const auto month{ToIntegral<uint8_t>(str.substr(5, 2))};
 113      const auto day{ToIntegral<uint8_t>(str.substr(8, 2))};
 114      const auto hour{ToIntegral<uint8_t>(str.substr(11, 2))};
 115      const auto min{ToIntegral<uint8_t>(str.substr(14, 2))};
 116      const auto sec{ToIntegral<uint8_t>(str.substr(17, 2))};
 117      if (!year || !month || !day || !hour || !min || !sec) {
 118          return {};
 119      }
 120      const std::chrono::year_month_day ymd{std::chrono::year{*year}, std::chrono::month{*month}, std::chrono::day{*day}};
 121      if (!ymd.ok()) {
 122          return {};
 123      }
 124      const auto time{std::chrono::hours{*hour} + std::chrono::minutes{*min} + std::chrono::seconds{*sec}};
 125      const auto tp{std::chrono::sys_days{ymd} + time};
 126      return int64_t{TicksSinceEpoch<std::chrono::seconds>(tp)};
 127  }
 128  
 129  std::string FormatISO8601Time(int64_t nTime)
 130  {
 131      const std::chrono::sys_seconds secs{std::chrono::seconds{nTime}};
 132      const auto days{std::chrono::floor<std::chrono::days>(secs)};
 133      const std::chrono::hh_mm_ss hms{secs - days};
 134      return strprintf("%02i:%02i:%02iZ", hms.hours().count(), hms.minutes().count(), hms.seconds().count());
 135  }
 136  
 137  struct timeval MillisToTimeval(int64_t nTimeout)
 138  {
 139      struct timeval timeout;
 140      timeout.tv_sec  = nTimeout / 1000;
 141      timeout.tv_usec = (nTimeout % 1000) * 1000;
 142      return timeout;
 143  }
 144  
 145  struct timeval MillisToTimeval(std::chrono::milliseconds ms)
 146  {
 147      return MillisToTimeval(count_milliseconds(ms));
 148  }
 149  
 150  std::chrono::nanoseconds ThreadCpuTime()
 151  {
 152  #ifdef CLOCK_THREAD_CPUTIME_ID
 153      timespec t;
 154      if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t) == -1) {
 155          return std::chrono::nanoseconds{0};
 156      }
 157      return std::chrono::seconds{t.tv_sec} + std::chrono::nanoseconds{t.tv_nsec};
 158  #elif defined(WIN32)
 159      FILETIME creation;
 160      FILETIME exit;
 161      FILETIME kernel;
 162      FILETIME user;
 163      // GetThreadTimes():
 164      // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes
 165      if (GetThreadTimes(GetCurrentThread(), &creation, &exit, &kernel, &user) == 0) {
 166          return std::chrono::nanoseconds{0};
 167      }
 168  
 169      // https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
 170      // "... you should copy the low- and high-order parts of the file time to a
 171      // ULARGE_INTEGER structure, perform 64-bit arithmetic on the QuadPart
 172      // member ..."
 173  
 174      ULARGE_INTEGER kernel_;
 175      kernel_.LowPart = kernel.dwLowDateTime;
 176      kernel_.HighPart = kernel.dwHighDateTime;
 177  
 178      ULARGE_INTEGER user_;
 179      user_.LowPart = user.dwLowDateTime;
 180      user_.HighPart = user.dwHighDateTime;
 181  
 182      // The units of the returned values from GetThreadTimes() are "100-nanosecond periods".
 183      // So, we multiply by 100 to get nanoseconds.
 184      return std::chrono::nanoseconds{(kernel_.QuadPart + user_.QuadPart) * 100};
 185  #else
 186      return std::chrono::nanoseconds{0};
 187  #endif
 188  }
 189  
 190  std::chrono::nanoseconds operator+=(std::atomic<std::chrono::nanoseconds>& a, std::chrono::nanoseconds b)
 191  {
 192      std::chrono::nanoseconds expected;
 193      std::chrono::nanoseconds desired;
 194      do {
 195          expected = a.load();
 196          desired = expected + b;
 197      } while (!a.compare_exchange_weak(expected, desired));
 198      return desired;
 199  }
 200