時間的概念
時間是線性的 均勻的, 同一時刻, 只有一個絕對只有一個時間值存在, 而時區(qū)的劃分 只是為了方便而已
GMT(Greenwich Mean Time)
在狹義的范圍下 時間的變化是勻速的, 為了描述時間, 我們也需要找到一個值,它的變化時均勻的, 最終選擇了太陽 按照太陽在一天當中所處的位置來描述當前時間, 但不同的地區(qū)太陽的位置并不一樣, 后來不同地區(qū)的文化為了交流方便, 選取了一個公共的大家認可的地方, 以這個地方太陽的位置來作參考, 最后選擇的是英國倫敦的格林尼治天文臺所在地,以格林尼治的時間作為公共時間,也就是我們所說的GMT時間
UTC(Coordinated Universal Time)
太陽所處的位置變化跟地球的自轉(zhuǎn)相關(guān),過去人們認為地球自轉(zhuǎn)的速率是恒定的,但在1960年這一認知被推翻了,人們發(fā)現(xiàn)地球自轉(zhuǎn)的速率正變得越來越慢,而時間前進的速率還是恒定的,所以GMT不再被認為可以用來精準的描述時間了。
我們需要繼續(xù)尋找一個勻速前進的值。抬頭看天是我們從宏觀方向去尋找答案,科技的發(fā)展讓我們在微觀方面取得了更深的認識,于是有聰明人根據(jù)微觀粒子原子的物理屬性,建立了原子鐘,以這種原子鐘來衡量時間的變化,原子鐘50億年才會誤差1秒,這種精讀已經(jīng)遠勝于GMT了。這個原子鐘所反映的時間,也就是我們現(xiàn)在所使用的UTC(Coordinated Universal Time )標準時間。
NSDate
NSDate對象描述的是時間線上的一個絕對的值,和時區(qū)和文化無關(guān),它參考的值是:以UTC為標準的,2001年一月一日00:00:00這一刻的時間絕對值。
這里有個概念很重要,我們用編程語言描述時間的時候,都是以一個時間線上的絕對值為參考點,參考點再加上偏移量(以秒或者毫秒,微秒,納秒為單位)來描述另外的時間點。
理解了這一點,再看NSDate的一些API調(diào)用就非常清楚了,比如:
NSDate* date = [NSDate date];
NSLog(@"current date: %@", date);
NSLog(@"current date interval: %f", [date timeIntervalSinceReferenceDate]);
NSDate和市區(qū)和文化無關(guān),所以要展示具體格式的時間,我們需要NSDateFormatter和NSTimeZone的輔助。
另外關(guān)于NSDate最重要的一點是:NSDate是受手機系統(tǒng)時間控制的。也就是說,當你修改了手機上的時間顯示,NSDate獲取當前時間的輸出也會隨之改變。在我們做App的時候,明白這一點,就知道NSDate并不可靠,因為用戶可能會修改它的值。
CFAbsoluteTimeGetCurrent()
CFAbsoluteTimeGetCurrent()的概念和NSDate非常相似,只不過參考點是:以GMT為標準的,2001年一月一日00:00:00這一刻的時間絕對值。
同樣CFAbsoluteTimeGetCurrent()也會跟著當前設(shè)備的系統(tǒng)時間一起變化,也可能會被用戶修改。
gettimeofday
struct timeval now;
struct timezone tz;
gettimeofday(&now, &tz);
NSLog(@"gettimeofday: %ld", now.tv_sec);
使用gettimeofday獲得的值是Unix time。Unix time又是什么呢?
Unix time是以UTC 1970年1月1號 00:00:00為基準時間,當前時間距離基準點偏移的秒數(shù)。上述API返回的值是1481266031,表示當前時間距離UTC 1970年1月1號 00:00:00一共過了1481266031秒。
NSDate也有一個API能返回Unix time
NSDate* date = [NSDate date];
NSLog(@"timeIntervalSince1970: %f", [date timeIntervalSince1970]);
gettimeofday和NSDate,CFAbsoluteTimeGetCurrent()一樣,都是受當前設(shè)備的系統(tǒng)時間影響。只不過是參考的時間基準點不一樣而已。我們和服務(wù)器通訊的時候一般使用Unix time。
mach_absolute_time()
前面提到我們需要找到一個均勻變化的屬性值來描述時間,而在我們的iPhone上剛好有一個這樣的值存在,就是CPU的時鐘周期數(shù)(ticks)。這個tick的數(shù)值可以用來描述時間,而mach_absolute_time()返回的就是CPU已經(jīng)運行的tick的數(shù)量。將這個tick數(shù)經(jīng)過一定的轉(zhuǎn)換就可以變成秒數(shù),或者納秒數(shù),這樣就和時間直接關(guān)聯(lián)了。
不過這個tick數(shù),在每次手機重啟之后,會重新開始計數(shù),而且iPhone鎖屏進入休眠之后tick也會暫停計數(shù)。
mach_absolute_time()不會受系統(tǒng)時間影響,只受設(shè)備重啟和休眠行為影響。
CACurrentMediaTime()
CACurrentMediaTime()就是將上面mach_absolute_time()的CPU tick數(shù)轉(zhuǎn)化成秒數(shù)的結(jié)果。以下代碼:
double mediaTime = CACurrentMediaTime();
NSLog(@"CACurrentMediaTime: %f", mediaTime);
返回的就是開機后設(shè)備一共運行了(設(shè)備休眠不統(tǒng)計在內(nèi))多少秒,另一個API也能返回相同的值:
NSTimeInterval systemUptime = [[NSProcessInfo processInfo] systemUptime];
NSLog(@"systemUptime: %f", systemUptime);
CACurrentMediaTime()也不會受系統(tǒng)時間影響,只受設(shè)備重啟和休眠行為影響。
sysctl
iOS系統(tǒng)記錄了上次設(shè)備重啟的時間. 可以通過如下API調(diào)用獲取:
#include <sys/sysctl.h>
- (long)bootTime
{
int mib[2];
size_t size;
struct timeval boottime;
mib[0] = CTL_KERN;
mib[1] = KERN_BOOTTIME;
size = sizeof(boottime);
if (sysctl(mib, MIB_SIZE, &boottime, &size, NULL, 0) != -1)
{
return boottime.tv_sec;
}
return 0;
}
返回的值是上次設(shè)備重啟的Unix time。
這個API返回的值也會受系統(tǒng)時間影響,用戶如果修改時間,值也會隨著變化。