chrono

Everything is inside the namespace std::chrono.

Differences between:
  • std::time_t

  • std::tm

  • std::time()

std::time() to get the number of elapsed seconds since the epoch time 1970.1.1 00:00:00. The returned type is time_t. Note its precision is in seconds.

std::localtime converts time_t to a struct tm in local time.

std::mktime() converts a struct tm into time_t in local time.

std::asctime() converts a struct tm into a char* in local time.

std::ctime() converts a time_t into a char* in local time.

std::strftime is more powerful.

std::this_thread::sleep_until takes a timepoint as argument, while std::this_thread::sleep_for takes a duration as argument.

After using namespace std::chrono_literals; or using std::chrono::operator""s, we can use auto s = 1s.

./code/chrono/main.cc
  1// Requires c++14
  2// g++ -std=c++14 main.cc
  3#include <assert.h>
  4#include <chrono>
  5#include <ctime>
  6#include <iostream>
  7#include <string>
  8#include <thread>
  9#include <type_traits>
 10#include <vector>
 11
 12void test_duration() {
 13  std::chrono::seconds s(1);
 14  static_assert(
 15      std::is_same<decltype(s),
 16                   std::chrono::duration<long long, std::ratio<1>>>::value,
 17      "");
 18  static_assert(sizeof(s) == sizeof(long long), "");
 19
 20  assert(s.count() == 1);
 21
 22  std::chrono::milliseconds ms(1);
 23  static_assert(
 24      std::is_same<decltype(ms), std::chrono::duration<
 25                                     long long, std::ratio<1, 1000>>>::value,
 26      "");
 27
 28  static_assert(sizeof(ms) == sizeof(long long), "");
 29
 30  assert(ms.count() == 1);
 31  ms = s; // implicit cast
 32  assert(ms.count() == 1000);
 33
 34  s = std::chrono::duration_cast<std::chrono::seconds>(ms);
 35  assert(s.count() == 1);
 36
 37  using namespace std::chrono_literals;
 38  auto s2 = 10s;
 39  static_assert(std::is_same<decltype(s), decltype(s2)>::value, "");
 40  assert(s2.count() == 10);
 41
 42  ms = s2;
 43  assert(ms.count() == 1e4);
 44  ms = ms + s;
 45  assert(ms.count() == 11000);
 46
 47  // s = 3; // error
 48  // std::cout << s << "\n"; // error
 49
 50  s = 1s;
 51  ms = 1ms;
 52  ms = s + ms;
 53  assert(ms.count() == 1001);
 54  s = std::chrono::duration_cast<std::chrono::seconds>(ms);
 55  assert(s.count() == 1);
 56
 57  ms = 1100ms;
 58  s = std::chrono::duration_cast<std::chrono::seconds>(ms); // truncated
 59  assert(s.count() == 1);
 60
 61  std::chrono::minutes m = 1min;
 62  s = m;
 63  assert(s.count() == 60);
 64
 65  std::chrono::hours h = 1h;
 66  s = h;
 67  assert(s.count() == 60 * 60);
 68
 69  std::chrono::seconds s3; // s3.count() is uninitialized
 70  // assert(s3.count() == 0); // does not hold
 71}
 72
 73void test_time_1() {
 74  // the resolution of std::time() is in seconds
 75  std::time_t t = std::time(nullptr);
 76  t = 1669039051;
 77  // 16690369051
 78  // 16690369052
 79  // 16690369053
 80  // t is an integer, representing the elapsed seconds since 1970.1.1 00:00 UTC
 81
 82  // the returned value points to a static allocated memory. Not thread safe.
 83  // it is overwritten in the next call
 84  std::tm *tm = std::localtime(&t);
 85
 86  // 2022-11-21 21:57:31
 87  printf("%d-%d-%d %d:%d:%d\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
 88         tm->tm_hour, tm->tm_min, tm->tm_sec);
 89  // tm_year, years since 1900
 90  // tm_mon: months since january (0-11)
 91  std::vector<std::string> days = {"sunday",    "saturday", "monday", "tuesday",
 92                                   "wednesday", "thursday", "friday"};
 93  // tm_wday: days since sunday (0-6)
 94  printf("weekday: %s, %d\n", days[tm->tm_wday].c_str(), tm->tm_wday);
 95  // weekday: saturday, 1
 96
 97  // tm_yday: days since january 1 (0-365)
 98  printf("day of the year: %d\n", tm->tm_yday);
 99  // day of the year: 324
100
101  // std::asctime() is not threadsafe
102  //
103  // Mon Nov 21 21:57:31 2022
104  printf("%s\n", std::asctime(tm));
105
106  // Mon Nov 21 13:57:31 2022
107  std::tm *gm = std::gmtime(&t); // UTC
108  printf("%s\n", std::asctime(gm));
109
110  // Mon Nov 21 21:57:31 2022
111  printf("%s\n", std::ctime(&t));
112  // std::ctime(&t) == std::asctime(std::localtime(&t))
113
114  // tm is in localtime
115  //
116  // https://en.cppreference.com/w/cpp/chrono/c/strftime
117  {
118    char s[100];
119    std::strftime(s, sizeof(s), "%Y", tm);
120    assert(s == std::string("2022"));
121  }
122
123  {
124    char s[100];
125    std::strftime(s, sizeof(s), "%y", tm);
126    assert(s == std::string("22")); // the last 2 digits of the year
127  }
128
129  {
130    char s[100];
131    std::strftime(s, sizeof(s), "%C", tm);
132    assert(s == std::string("20")); // the first 2 digits of the year
133  }
134
135  {
136    char s[100];
137    std::strftime(s, sizeof(s), "%b", tm);
138    assert(s == std::string("Nov"));
139  }
140
141  {
142    char s[100];
143    std::strftime(s, sizeof(s), "%B", tm);
144    assert(s == std::string("November"));
145  }
146
147  {
148    char s[100];
149    std::strftime(s, sizeof(s), "%m", tm);
150    assert(s == std::string("11")); // month
151  }
152
153  {
154    char s[100];
155    std::strftime(s, sizeof(s), "%U", tm);
156    // week of the year. Sunday is the first day of the week
157    assert(s == std::string("47"));
158  }
159
160  {
161    char s[100];
162    std::strftime(s, sizeof(s), "%W", tm);
163    // week of the year. Monday is the first day of the week
164    assert(s == std::string("47"));
165  }
166
167  {
168    char s[100];
169    std::strftime(s, sizeof(s), "%j", tm);
170    // day of the year: 1-366
171    assert(s == std::string("325"));
172  }
173
174  {
175    char s[100];
176    std::strftime(s, sizeof(s), "%d", tm);
177    // day of the month: 1-31
178    assert(s == std::string("21"));
179  }
180}
181
182void test_time_2() {
183  struct std::tm tm {};
184  tm.tm_year = 1970 - 1900;
185  tm.tm_mon = 0;
186  tm.tm_mday = 1;
187  tm.tm_sec = 1;
188  tm.tm_isdst = 0;
189  // Cannot use std::mktime() here since it treats tm as localtime
190  // std::time_t t = std::mktime(&tm);
191
192  std::time_t t = timegm(&tm);
193  assert(t == 1); // epoch time is 1970, january 1, 00:00:00
194}
195
196void test_timepoint() {
197  {
198    // conversion between timepoint and time_t
199    std::time_t t = std::time(nullptr);
200
201    std::chrono::system_clock::time_point tp =
202        std::chrono::system_clock::from_time_t(t);
203
204    auto duration = tp.time_since_epoch();
205    auto s = std::chrono::duration_cast<std::chrono::seconds>(duration);
206    assert(t == s.count());
207  }
208
209  {
210    std::chrono::system_clock::time_point now =
211        std::chrono::system_clock::now();
212    std::time_t t = std::chrono::system_clock::to_time_t(now);
213    std::time_t t2 = std::time(nullptr);
214    assert(t == t2);
215  }
216}
217
218void test_sleep() {
219  std::time_t t = std::time(nullptr);
220  // note: std::ctime contains "\n"
221  std::cout << "start to sleep at " << std::ctime(&t);
222  auto now = std::chrono::steady_clock::now();
223  using std::chrono::operator""s;
224  std::this_thread::sleep_until(now + 1s);
225  t = std::time(nullptr);
226  std::cout << "finish sleeping at " << std::ctime(&t);
227}
228
229void test_sleep_2() {
230  auto start = std::chrono::steady_clock::now();
231  using std::chrono::operator""ms;
232  // use sleep_until with a timepoint
233  std::this_thread::sleep_until(start + 500ms);
234  auto end = std::chrono::steady_clock::now();
235  std::cout << "finish sleeping at "
236            << std::chrono::duration<double, std::milli>(end - start).count()
237            << " ms\n";
238}
239
240void test_sleep_3() {
241  auto start = std::chrono::steady_clock::now();
242  using std::chrono::operator""ms;
243  // use sleep_for with a duration
244  std::this_thread::sleep_for(10ms);
245  auto end = std::chrono::steady_clock::now();
246  std::cout << "finish sleeping at "
247            << std::chrono::duration<double, std::milli>(end - start).count()
248            << " ms\n";
249}
250
251int main() {
252  test_duration();
253  test_time_1();
254  test_time_2();
255  test_timepoint();
256  test_sleep();
257  test_sleep_2();
258  test_sleep_3();
259  return 0;
260}