因为底层逻辑实现不一样操做系统区别很大,因此干脆分篇来讲。
主要讲一下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真是一坨屎,根本跟微软无法比。