获取系统信息1——linux系统中的时间
以下內(nèi)容源于朱有鵬《物聯(lián)網(wǎng)大講堂》課程的學(xué)習(xí)整理,如有侵權(quán),請(qǐng)告知?jiǎng)h除。
一、關(guān)于時(shí)間的概念
1、GMT時(shí)間
- GMT是格林尼治時(shí)間,也就是格林尼治地區(qū)的當(dāng)?shù)貢r(shí)間;
- 用格林尼治的當(dāng)?shù)貢r(shí)間作為全球國(guó)際時(shí)間,用以描述全球性的事件的時(shí)間,方便大家記憶。
- 選這個(gè)地區(qū),是因?yàn)樗翘煳膶W(xué)發(fā)源地。
2、UTC時(shí)間
- GMT時(shí)間是以前使用的,近些年使用UTC時(shí)間;
- 參考http://www.cnblogs.com/qiuyi21/archive/2008/03/04/1089456.html。
3、計(jì)算機(jī)中與時(shí)間有關(guān)的部件
- 點(diǎn)時(shí)間和段時(shí)間,段時(shí)間=點(diǎn)時(shí)間-點(diǎn)時(shí)間
- 定時(shí)器和實(shí)時(shí)時(shí)鐘,定時(shí)器(timer)定的時(shí)間就是段時(shí)間,實(shí)時(shí)時(shí)鐘(RTC)是和點(diǎn)時(shí)間有關(guān)的一個(gè)器件。
二、linux系統(tǒng)中的時(shí)間
1、jiffies的引入
- jiffies是linux內(nèi)核中的一個(gè)全局變量,是(以內(nèi)核的節(jié)拍時(shí)間為單位時(shí)間)一個(gè)數(shù)值,由此數(shù)值可以知道過(guò)了多少個(gè)節(jié)拍;
- 內(nèi)核配置時(shí)定義了一個(gè)節(jié)拍時(shí)間,linux內(nèi)核的調(diào)度系統(tǒng)工作時(shí),以這個(gè)節(jié)拍時(shí)間為時(shí)間片;
- 開(kāi)機(jī)時(shí),jiffies變量有一個(gè)基準(zhǔn)值,然后內(nèi)核每過(guò)一個(gè)節(jié)拍時(shí)間jiffies就會(huì)加1。
2、linux系統(tǒng)如何記錄時(shí)間
(1)開(kāi)機(jī)啟動(dòng)時(shí),內(nèi)核會(huì)讀取RTC硬件(斷電會(huì)繼續(xù)運(yùn)行,有電池),獲取一個(gè)時(shí)間作為初始基準(zhǔn)時(shí)間
- 這個(gè)基準(zhǔn)時(shí)間對(duì)應(yīng)一個(gè)jiffies值;
- 這個(gè)基準(zhǔn)時(shí)間換算成jiffies值的方法:用這個(gè)時(shí)間減去1970-01-01 00:00:00 +0000(UTC),然后把這個(gè)時(shí)間段換算成jiffies數(shù)值。
- 這個(gè)jiffies值作為我們開(kāi)機(jī)時(shí)的基準(zhǔn)jiffies值存在;
- 系統(tǒng)運(yùn)行時(shí),每個(gè)時(shí)鐘節(jié)拍的末尾都會(huì)給jiffies這個(gè)全局變量加1,因此操作系統(tǒng)就使用jiffies這個(gè)全局變量記錄當(dāng)前的時(shí)間。
- 當(dāng)需要當(dāng)前時(shí)間點(diǎn)時(shí),就用jiffies這個(gè)時(shí)間點(diǎn)去計(jì)算;
- 計(jì)算方法:先把當(dāng)前的jiffies值對(duì)應(yīng)的時(shí)間段算出來(lái),然后加上1970-01-01 00:00:00 +0000(UTC)即可得到這個(gè)時(shí)間點(diǎn)。
(2)操作系統(tǒng)只在開(kāi)機(jī)時(shí)讀一次RTC
- 整個(gè)系統(tǒng)運(yùn)行過(guò)程中RTC是無(wú)作用的,RTC的真正作用是在OS的2次開(kāi)機(jī)之間進(jìn)行時(shí)間的保存。
(3)理解要點(diǎn)
- jiffies這個(gè)變量記錄的是段時(shí)間(即當(dāng)前時(shí)間和1970-01-01 00:00:00 +0000(UTC)這個(gè)時(shí)間的差值);
- 一個(gè)時(shí)間節(jié)拍的時(shí)間取決于操作系統(tǒng)的配置,現(xiàn)代linux系統(tǒng)一般是10ms或者1ms。
- 這個(gè)時(shí)間其實(shí)就是調(diào)度時(shí)間,在內(nèi)核中用HZ來(lái)記錄和表示。如果HZ定義成1000,則時(shí)鐘節(jié)拍就是1/HZ,也就是1ms。
3、linux中時(shí)間相關(guān)的系統(tǒng)調(diào)用
(1)常用的時(shí)間相關(guān)的API和C庫(kù)函數(shù)有9個(gè)
- time、ctime、localtime、gmtime、mktime、asctime、strftime、gettimeofday、settimeofday;
(2)time系統(tǒng)調(diào)用返回(當(dāng)前時(shí)間距離1970-01-01 00:00:00 +0000(UTC)的)秒數(shù)
- time內(nèi)部用jiffies換算得到秒數(shù);
- 其他函數(shù)基本都是圍繞著time來(lái)工作的;
(3)gmtime、localtime把time得到的秒數(shù)變成一個(gè)struct tm結(jié)構(gòu)體表示的時(shí)間
- gmtime得到的是國(guó)際時(shí)間,而localtime得到的是本地(運(yùn)行l(wèi)ocaltime函數(shù)的程序所在的計(jì)算機(jī)所設(shè)置的時(shí)區(qū)對(duì)應(yīng)的本地時(shí)間)時(shí)間;
- mktime用來(lái)完成相反方向的轉(zhuǎn)換(struct tm到time_t);
(4)如果想從struct tm出發(fā),得到字符串格式的時(shí)間,可以用asctime或者strftime;如果想從time_t出發(fā),得到字符串格式的時(shí)間,用ctime。
(5)gettimeofday返回的時(shí)間
- 由struct timeval和struct timezone這兩個(gè)結(jié)構(gòu)體來(lái)共同表示的,其中timeval表示時(shí)間,而timezone表示時(shí)區(qū);
- settimeofday是用來(lái)設(shè)置當(dāng)前的時(shí)間和時(shí)區(qū)的;
(6)總結(jié)
- 不管使用哪個(gè)系統(tǒng)調(diào)用,最終得到的時(shí)間本質(zhì)上都是一個(gè)時(shí)間(這個(gè)時(shí)間最終都是從kernel中記錄的jiffies中計(jì)算得來(lái)的);
- 不同的函數(shù)返回的時(shí)間的格式不同,精度不同。
三、時(shí)間相關(guān)API實(shí)戰(zhàn)
1、time
- time能得到一個(gè)當(dāng)前時(shí)間距離標(biāo)準(zhǔn)起點(diǎn)時(shí)間1970-01-01 00:00:00 +0000(UTC)過(guò)去了多少秒
2、ctime
- ctime可以從time_t出發(fā)得到一個(gè)容易觀察的字符串格式的當(dāng)前時(shí)間;
- ctime好處是很簡(jiǎn)單好用,可以直接得到當(dāng)前時(shí)間的字符串格式,直接打印來(lái)看。
- 壞處是ctime的打印時(shí)間格式是固定的,沒(méi)法按照我們的想法去變。
- ctime函數(shù)得到的時(shí)間考慮了計(jì)算機(jī)中的本地時(shí)間的(計(jì)算機(jī)中的時(shí)區(qū)設(shè)置)。
3、gmtime和localtime
- gmtime獲取的時(shí)間中:年份是以1970為基準(zhǔn)的差值,月份是0表示1月,小時(shí)數(shù)是以UTC時(shí)間的0時(shí)區(qū)為標(biāo)準(zhǔn)的小時(shí)數(shù)。
- localtime和gmtime的唯一區(qū)別就是localtime以當(dāng)前計(jì)算機(jī)中設(shè)置的時(shí)區(qū)為小時(shí)的時(shí)間基準(zhǔn),其余一樣。實(shí)踐證明我們的猜測(cè)是正確的。
4、mktime
- 從OS中讀取時(shí)間時(shí)用不到mktime的,這個(gè)mktime是用來(lái)向操作系統(tǒng)設(shè)置時(shí)間時(shí)用的。
5、asctime
- asctime得到一個(gè)固定格式的字符串格式的當(dāng)前時(shí)間,效果上和ctime一樣的。
- 區(qū)別是ctime從time_t出發(fā),而asctime從struct tm出發(fā)。
6、strftime
- asctime和ctime得到的時(shí)間字符串都是固定格式的,沒(méi)法用戶自定義格式;
- 如果需要用戶自定義時(shí)間的格式,則需要用strftime。
7、gettimeofday和settimeofday
- 前面講到的基于time函數(shù)的那個(gè)系列都是以秒為單位來(lái)獲取時(shí)間的,沒(méi)有比秒更精確的時(shí)間;
- 有時(shí)候希望得到非常精確的時(shí)間(譬如以u(píng)s為單位),只能通過(guò)gettimeofday來(lái)實(shí)現(xiàn)。
8、代碼
#include <stdio.h> #include <time.h> #include <string.h> #include <sys/time.h>int main(void) {time_t tNow = -1;struct tm tmNow;char buf[100];struct timeval tv = {0};struct timezone tz = {0};int ret = -1;// time//tNow = time(NULL); // 返回值time(&tNow); // 指針做輸出型參數(shù)if (tNow < 0){perror("time");return -1;}printf("time: %ld.\n", tNow);// ctimeprintf("ctime: %s.\n", ctime(&tNow));//ctime可以從time_t出發(fā)得到一個(gè)容易觀察的字符串格式的當(dāng)前時(shí)間; #if 0 // gmtime 和localtimememset(&tmNow, 0, sizeof(tmNow));gmtime_r(&tNow, &tmNow);printf("年%d月%d日%d時(shí)%d.\n", tmNow.tm_year, tmNow.tm_mon, tmNow.tm_mday, tmNow.tm_hour);//可重入版本的,不用在子函數(shù)內(nèi)部申請(qǐng)空間,而是結(jié)構(gòu)體在外部申請(qǐng)空間后,結(jié)構(gòu)體作為傳參傳入//因此之前必須menset。//對(duì)比不可重入的,一般是在子函數(shù)內(nèi)部為結(jié)構(gòu)體申請(qǐng)空間。memset(&tmNow, 0, sizeof(tmNow));localtime_r(&tNow, &tmNow);printf("年%d月%d日%d時(shí)%d.\n", tmNow.tm_year, tmNow.tm_mon, tmNow.tm_mday, tmNow.tm_hour); #endif#if 0// asctimememset(&tmNow, 0, sizeof(tmNow));localtime_r(&tNow, &tmNow);printf("年%d月%d日%d時(shí)%d.\n", tmNow.tm_year, tmNow.tm_mon, tmNow.tm_mday, tmNow.tm_hour);printf("asctime:%s.\n", asctime(&tmNow)); #endif#if 0// strftimememset(&tmNow, 0, sizeof(tmNow));localtime_r(&tNow, &tmNow);printf("年%d月%d日%d時(shí)%d.\n", tmNow.tm_year, tmNow.tm_mon, tmNow.tm_mday, tmNow.tm_hour);memset(buf, 0, sizeof(buf));strftime(buf, sizeof(buf), "%Y * %m * %d, %H-%M-%S.", &tmNow);printf("時(shí)間為:[%s].\n", buf); #endif// gettimeofdayret = gettimeofday(&tv, &tz);if (ret < 0){perror("gettimeofday");return -1;}printf("seconde: %ld.\n", tv.tv_sec);printf("timezone:%d.\n", tz.tz_minuteswest);return 0; }創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
總結(jié)
以上是生活随笔為你收集整理的获取系统信息1——linux系统中的时间的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Proxmark3的Android客户端
- 下一篇: Android实现TCP客户端