因爲底層邏輯實現不一樣操做系統區別很大,因此乾脆分篇來講。
主要講一下Time、TimeTicks兩個類裏面對於時間戳的實現,其他的運算符重載、邊緣工具方法就不看了,先是Time。
class V8_BASE_EXPORT Time final : public time_internal::TimeBase<Time> {
public:
// Contains the nullptr time. Use Time::Now() to get the current time.
constexpr Time() : TimeBase(0) {}
// Returns the current time. Watch out, the system might adjust its clock
// in which case time will actually go backwards. We don't guarantee that
// times are increasing, or that two calls to Now() won't be the same.
static Time Now();
// Returns the current time. Same as Now() except that this function always
// uses system time so that there are no discrepancies between the returned
// time and system time even on virtual environments including our test bot.
// For timing sensitive unittests, this function should be used.
static Time NowFromSystemTime();
// ...
};複製代碼
從註釋可知,這裏的Now是返回國際時間戳的通用方法,可是操做系統可能會對返回值作修正,因此是有必定風險的。第二個NowFromSystemTime使用的系統時間比較準確,求精確的狀況下考慮使用這一個。
#elif V8_OS_POSIX
Time Time::Now() {
}
Time Time::NowFromSystemTime() {
return Now();
}複製代碼
這就很蠢了,多是該操做系統不存在修正時間戳的狀況,因此不必分辨這兩個方法了。
因此對於兩種方式的解析就變成了一個,集中來看Now的實現。
Time Time::Now() {
struct timeval tv;
int result = gettimeofday(&tv, nullptr);
DCHECK_EQ(0, result);
USE(result);
return FromTimeval(tv);
}複製代碼
這裏的用的都是Linux內置的方法,timeval結構體專門用來獲取返回的時間,能夠精確到微秒,也就是秒/毫秒/微秒的精度。
結構體兩部分分別保存當前時間戳的秒部分、微秒部分,類型均爲long,下面用一個簡單例子來展現。
int main() {
struct timeval tv;
gettimeofday(&tv, nullptr);
cout << "current seconds is " << tv.tv_sec << endl;
cout << "current microseconds is " <<tv.tv_usec << endl;
}複製代碼
在瀏覽器下面同時用Date.now()作一個對比,因爲仍是有必定的時間差,因此微秒部分確定對不上的。
在秒的部分徹底對上了,微秒那塊就別在乎了,我可沒有神手速。
這樣,就經過系統API獲得了當前時間戳,下面就是對兩個部分作一個處理。
Time Time::FromTimeval(struct timeval tv) {
DCHECK_GE(tv.tv_usec, 0);
DCHECK(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond));
if (tv.tv_usec == 0 && tv.tv_sec == 0) {
return Time();
}
if (tv.tv_usec == static_cast<suseconds_t>(kMicrosecondsPerSecond - 1) &&
tv.tv_sec == std::numeric_limits<time_t>::max()) {
return Max();
}
return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec);
}複製代碼
比較簡單,看一下注釋就懂了,最後返回的是以微秒爲單位的一個長整數,而JS中的Date.now()返回的則是毫秒單位,略有不一樣。
class V8_BASE_EXPORT TimeTicks final : public time_internal::TimeBase<TimeTicks> {
public:
constexpr TimeTicks() : TimeBase(0) {}
static TimeTicks Now();
static TimeTicks HighResolutionNow();
static bool IsHighResolution();
private:
friend class time_internal::TimeBase<TimeTicks>;
explicit constexpr TimeTicks(int64_t ticks) : TimeBase(ticks) {}
};複製代碼
這個類看看就行了,跟上面那個相似,也有兩個方法,一個是更精確的。
然而,兩個方法也是一個,在mac上不存在精細度(windows上都有區別,下篇搞),V8在內部直接寫了以下注釋。
#error platform does not implement TimeTicks::HighResolutionNow.
struct mach_timebase_info {
uint32_t numer;
uint32_t denom;
};
TimeTicks TimeTicks::Now() {
int64_t ticks;
static struct mach_timebase_info info;
if (info.denom == 0) {
kern_return_t result = mach_timebase_info(&info);
}
ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond * info.numer / info.denom);
return TimeTicks(ticks + 1);
}複製代碼
這裏涉及2個內置方法和1個內置結構體,挨個介紹一下。
-
mach_timebase_info結構體做爲參數傳入同名函數
-
mach_timebase_info方法返回兩個因子,將返回的分子除以分母能夠獲得一個基準參數(找不到Linux的官方API文檔,仍是windows好啊),具體解釋有興趣能夠去查看
-
mach_absolute_time方法返回一個系統從啓動開始保持運行的一個絕對時間,參考windows的QPC,單位爲納秒
惟一有價值的就是那個單位,因爲返回的絕對時間單位是納秒,因此須要除以TimeConstants裏面的常數,最後與基準參數相乘,最終獲得一個硬件時間戳。
int main() {
static struct mach_timebase_info info;
mach_timebase_info(&info);
cout << "numer is " << info.numer << endl;
cout << "denom is " << info.denom << endl;
cout << "absolute time is " << mach_absolute_time() << endl;
cout << "current timestamp is " << (info.numer / info.denom) * (mach_absolute_time() * 1e-9) << endl;
}複製代碼
這樣獲得最終的結果理論上就是我mac電腦的活躍秒數。
7000秒,也就是大約2個小時吧,看來仍是很準確的,有興趣的能夠自行實驗。
下一篇換windows,apple的
apidoc真是一坨屎,根本跟微軟無法比。