1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "platform/api/time.h"
6 
7 #include <chrono>
8 #include <ctime>
9 #include <ratio>
10 
11 #include "util/chrono_helpers.h"
12 #include "util/osp_logging.h"
13 
14 using std::chrono::high_resolution_clock;
15 using std::chrono::steady_clock;
16 using std::chrono::system_clock;
17 
18 namespace openscreen {
19 
now()20 Clock::time_point Clock::now() noexcept {
21   constexpr bool can_use_steady_clock =
22       std::ratio_less_equal<steady_clock::period,
23                             Clock::kRequiredResolution>::value;
24   constexpr bool can_use_high_resolution_clock =
25       std::ratio_less_equal<high_resolution_clock::period,
26                             Clock::kRequiredResolution>::value &&
27       high_resolution_clock::is_steady;
28   static_assert(can_use_steady_clock || can_use_high_resolution_clock,
29                 "no suitable default clock on this platform");
30 
31   // Choose whether to use the steady_clock or the high_resolution_clock. The
32   // general assumption here is that steady_clock will be the lesser expensive
33   // to use. Only fall-back to high_resolution_clock if steady_clock does not
34   // meet the resolution requirement.
35   //
36   // Note: Most of the expression below should be reduced at compile-time (by
37   // any half-decent optimizing compiler), and so there won't be any branching
38   // or significant math actually taking place here.
39   if (can_use_steady_clock) {
40     return Clock::time_point(
41         Clock::to_duration(steady_clock::now().time_since_epoch()));
42   }
43   return Clock::time_point(
44       Clock::to_duration(high_resolution_clock::now().time_since_epoch()));
45 }
46 
GetWallTimeSinceUnixEpoch()47 std::chrono::seconds GetWallTimeSinceUnixEpoch() noexcept {
48   // Note: Even though std::time_t is not necessarily "seconds since UNIX epoch"
49   // before C++20, it is almost universally implemented that way on all
50   // platforms. There is a unit test to confirm this behavior, so don't worry
51   // about it here.
52   const std::time_t since_epoch = system_clock::to_time_t(system_clock::now());
53 
54   // std::time_t is unspecified by the spec. If it's only a 32-bit integer, it's
55   // possible that values will overflow in early 2038. Warn future developers a
56   // year ahead of time.
57   if (sizeof(std::time_t) <= 4) {
58     constexpr std::time_t a_year_before_overflow =
59         std::numeric_limits<std::time_t>::max() -
60         to_seconds(365 * hours(24)).count();
61     OSP_DCHECK_LE(since_epoch, a_year_before_overflow);
62   }
63 
64   return std::chrono::seconds(since_epoch);
65 }
66 
67 }  // namespace openscreen
68