xref: /aosp_15_r20/external/webrtc/rtc_base/time_utils.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include <stdint.h>
12 
13 #if defined(WEBRTC_POSIX)
14 #include <sys/time.h>
15 #endif
16 
17 #if defined(WEBRTC_WIN)
18 #include <sys/timeb.h>
19 #endif
20 
21 #include "rtc_base/checks.h"
22 #include "rtc_base/numerics/safe_conversions.h"
23 #include "rtc_base/system_time.h"
24 #include "rtc_base/time_utils.h"
25 
26 namespace rtc {
27 
28 ClockInterface* g_clock = nullptr;
29 
SetClockForTesting(ClockInterface * clock)30 ClockInterface* SetClockForTesting(ClockInterface* clock) {
31   ClockInterface* prev = g_clock;
32   g_clock = clock;
33   return prev;
34 }
35 
GetClockForTesting()36 ClockInterface* GetClockForTesting() {
37   return g_clock;
38 }
39 
40 #if defined(WINUWP)
41 
42 namespace {
43 
44 class TimeHelper final {
45  public:
46   TimeHelper(const TimeHelper&) = delete;
47 
48   // Resets the clock based upon an NTP server. This routine must be called
49   // prior to the main system start-up to ensure all clocks are based upon
50   // an NTP server time if NTP synchronization is required. No critical
51   // section is used thus this method must be called prior to any clock
52   // routines being used.
SyncWithNtp(int64_t ntp_server_time_ms)53   static void SyncWithNtp(int64_t ntp_server_time_ms) {
54     auto& singleton = Singleton();
55     TIME_ZONE_INFORMATION time_zone;
56     GetTimeZoneInformation(&time_zone);
57     int64_t time_zone_bias_ns =
58         rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000;
59     singleton.app_start_time_ns_ =
60         (ntp_server_time_ms - kNTPTimeToUnixTimeEpochOffset) * 1000000 -
61         time_zone_bias_ns;
62     singleton.UpdateReferenceTime();
63   }
64 
65   // Returns the number of nanoseconds that have passed since unix epoch.
TicksNs()66   static int64_t TicksNs() {
67     auto& singleton = Singleton();
68     int64_t result = 0;
69     LARGE_INTEGER qpcnt;
70     QueryPerformanceCounter(&qpcnt);
71     result = rtc::dchecked_cast<int64_t>(
72         (rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 /
73          rtc::dchecked_cast<uint64_t>(singleton.os_ticks_per_second_)) *
74         10000);
75     result = singleton.app_start_time_ns_ + result -
76              singleton.time_since_os_start_ns_;
77     return result;
78   }
79 
80  private:
TimeHelper()81   TimeHelper() {
82     TIME_ZONE_INFORMATION time_zone;
83     GetTimeZoneInformation(&time_zone);
84     int64_t time_zone_bias_ns =
85         rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000;
86     FILETIME ft;
87     // This will give us system file in UTC format.
88     GetSystemTimeAsFileTime(&ft);
89     LARGE_INTEGER li;
90     li.HighPart = ft.dwHighDateTime;
91     li.LowPart = ft.dwLowDateTime;
92 
93     app_start_time_ns_ = (li.QuadPart - kFileTimeToUnixTimeEpochOffset) * 100 -
94                          time_zone_bias_ns;
95 
96     UpdateReferenceTime();
97   }
98 
Singleton()99   static TimeHelper& Singleton() {
100     static TimeHelper singleton;
101     return singleton;
102   }
103 
UpdateReferenceTime()104   void UpdateReferenceTime() {
105     LARGE_INTEGER qpfreq;
106     QueryPerformanceFrequency(&qpfreq);
107     os_ticks_per_second_ = rtc::dchecked_cast<int64_t>(qpfreq.QuadPart);
108 
109     LARGE_INTEGER qpcnt;
110     QueryPerformanceCounter(&qpcnt);
111     time_since_os_start_ns_ = rtc::dchecked_cast<int64_t>(
112         (rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 /
113          rtc::dchecked_cast<uint64_t>(os_ticks_per_second_)) *
114         10000);
115   }
116 
117  private:
118   static constexpr uint64_t kFileTimeToUnixTimeEpochOffset =
119       116444736000000000ULL;
120   static constexpr uint64_t kNTPTimeToUnixTimeEpochOffset = 2208988800000L;
121 
122   // The number of nanoseconds since unix system epoch
123   int64_t app_start_time_ns_;
124   // The number of nanoseconds since the OS started
125   int64_t time_since_os_start_ns_;
126   // The OS calculated ticks per second
127   int64_t os_ticks_per_second_;
128 };
129 
130 }  // namespace
131 
SyncWithNtp(int64_t time_from_ntp_server_ms)132 void SyncWithNtp(int64_t time_from_ntp_server_ms) {
133   TimeHelper::SyncWithNtp(time_from_ntp_server_ms);
134 }
135 
WinUwpSystemTimeNanos()136 int64_t WinUwpSystemTimeNanos() {
137   return TimeHelper::TicksNs();
138 }
139 
140 #endif  // defined(WINUWP)
141 
SystemTimeMillis()142 int64_t SystemTimeMillis() {
143   return static_cast<int64_t>(SystemTimeNanos() / kNumNanosecsPerMillisec);
144 }
145 
TimeNanos()146 int64_t TimeNanos() {
147   if (g_clock) {
148     return g_clock->TimeNanos();
149   }
150   return SystemTimeNanos();
151 }
152 
Time32()153 uint32_t Time32() {
154   return static_cast<uint32_t>(TimeNanos() / kNumNanosecsPerMillisec);
155 }
156 
TimeMillis()157 int64_t TimeMillis() {
158   return TimeNanos() / kNumNanosecsPerMillisec;
159 }
160 
TimeMicros()161 int64_t TimeMicros() {
162   return TimeNanos() / kNumNanosecsPerMicrosec;
163 }
164 
TimeAfter(int64_t elapsed)165 int64_t TimeAfter(int64_t elapsed) {
166   RTC_DCHECK_GE(elapsed, 0);
167   return TimeMillis() + elapsed;
168 }
169 
TimeDiff32(uint32_t later,uint32_t earlier)170 int32_t TimeDiff32(uint32_t later, uint32_t earlier) {
171   return later - earlier;
172 }
173 
TimeDiff(int64_t later,int64_t earlier)174 int64_t TimeDiff(int64_t later, int64_t earlier) {
175   return later - earlier;
176 }
177 
TimestampWrapAroundHandler()178 TimestampWrapAroundHandler::TimestampWrapAroundHandler()
179     : last_ts_(0), num_wrap_(-1) {}
180 
Unwrap(uint32_t ts)181 int64_t TimestampWrapAroundHandler::Unwrap(uint32_t ts) {
182   if (num_wrap_ == -1) {
183     last_ts_ = ts;
184     num_wrap_ = 0;
185     return ts;
186   }
187 
188   if (ts < last_ts_) {
189     if (last_ts_ >= 0xf0000000 && ts < 0x0fffffff)
190       ++num_wrap_;
191   } else if ((ts - last_ts_) > 0xf0000000) {
192     // Backwards wrap. Unwrap with last wrap count and don't update last_ts_.
193     return ts + (num_wrap_ - 1) * (int64_t{1} << 32);
194   }
195 
196   last_ts_ = ts;
197   return ts + (num_wrap_ << 32);
198 }
199 
TmToSeconds(const tm & tm)200 int64_t TmToSeconds(const tm& tm) {
201   static short int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
202   static short int cumul_mdays[12] = {0,   31,  59,  90,  120, 151,
203                                       181, 212, 243, 273, 304, 334};
204   int year = tm.tm_year + 1900;
205   int month = tm.tm_mon;
206   int day = tm.tm_mday - 1;  // Make 0-based like the rest.
207   int hour = tm.tm_hour;
208   int min = tm.tm_min;
209   int sec = tm.tm_sec;
210 
211   bool expiry_in_leap_year =
212       (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
213 
214   if (year < 1970)
215     return -1;
216   if (month < 0 || month > 11)
217     return -1;
218   if (day < 0 || day >= mdays[month] + (expiry_in_leap_year && month == 2 - 1))
219     return -1;
220   if (hour < 0 || hour > 23)
221     return -1;
222   if (min < 0 || min > 59)
223     return -1;
224   if (sec < 0 || sec > 59)
225     return -1;
226 
227   day += cumul_mdays[month];
228 
229   // Add number of leap days between 1970 and the expiration year, inclusive.
230   day += ((year / 4 - 1970 / 4) - (year / 100 - 1970 / 100) +
231           (year / 400 - 1970 / 400));
232 
233   // We will have added one day too much above if expiration is during a leap
234   // year, and expiration is in January or February.
235   if (expiry_in_leap_year && month <= 2 - 1)  // `month` is zero based.
236     day -= 1;
237 
238   // Combine all variables into seconds from 1970-01-01 00:00 (except `month`
239   // which was accumulated into `day` above).
240   return (((static_cast<int64_t>(year - 1970) * 365 + day) * 24 + hour) * 60 +
241           min) *
242              60 +
243          sec;
244 }
245 
TimeUTCMicros()246 int64_t TimeUTCMicros() {
247   if (g_clock) {
248     return g_clock->TimeNanos() / kNumNanosecsPerMicrosec;
249   }
250 #if defined(WEBRTC_POSIX)
251   struct timeval time;
252   gettimeofday(&time, nullptr);
253   // Convert from second (1.0) and microsecond (1e-6).
254   return (static_cast<int64_t>(time.tv_sec) * rtc::kNumMicrosecsPerSec +
255           time.tv_usec);
256 
257 #elif defined(WEBRTC_WIN)
258   struct _timeb time;
259   _ftime(&time);
260   // Convert from second (1.0) and milliseconds (1e-3).
261   return (static_cast<int64_t>(time.time) * rtc::kNumMicrosecsPerSec +
262           static_cast<int64_t>(time.millitm) * rtc::kNumMicrosecsPerMillisec);
263 #endif
264 }
265 
TimeUTCMillis()266 int64_t TimeUTCMillis() {
267   return TimeUTCMicros() / kNumMicrosecsPerMillisec;
268 }
269 
270 }  // namespace rtc
271