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