mktime很慢就自己去實現一個吧


mktime很慢就自己去實現一個吧

標簽(空格分隔): Linux C語言


1. 前言

  • 最近遇到一個轉換數據的程序,只是一些內存操作,但是程序表現的巨慢,導致上線之后要天天盯着是否正常。忍不了,就使用gprofiler分析了一波,發現的結果是一個時間轉換上十分耗時(占比達到90%多)

  • mktime是用來把字符串時間(YYYYMMDD-HH:MM:SS)轉換為unix時間戳的

2. 慢的原因

根據后面自己的測試和前輩說的總結下:

  • 根據我的測試發現,我自己寫的函數都是在用戶態下的耗時,而mktime的有一半時間是在內核態的耗時。
  • 前輩說:“這個函數有鎖的。” 具體未知,有時間去探索下。

3. 自己實現一個

  • 番外:轉自漫畫:程序員的日常:時間戳和時區的故事 
    1.時間戳:指的就是Unix時間戳(Unix timestamp)。它也被稱為Unix時間(Unix time)、POSIX時間(POSIX time),是一種時間表示方式,定義為從格林威治時間1970年01月01日00時00分00秒起至現在的總秒數。因此,嚴格來說,不管你處在地球上的哪個地方,任意時間點的時間戳都是相同的。這點有利於線上和客戶端分布式應用統一追蹤時間信息。 
    2.時區:中國時區是東8區 
    時間戳.png-493.5kB

    時間戳相同的根本原因是因為時區,這么想,時間戳相同,那么我們可以轉換自己本地時間的時候就需要一個偏移來,那就是時區的作用了。同樣在實現本地時間字符串轉換為時間戳的時候,也需要加入時區的偏移來還原時間戳。后面會在代碼中說清楚。 
    UTC,GMT等時間參考:時間:UTC時間、GMT時間、本地時間、Unix時間戳

  • 實現 
    參考:“mktime” slow? use custom function. 
    主要實現是使用c語言的 struct tm結構體和時間戳時區關系來計算就好了。 
    代碼是參考上面博主的,但是他的代碼存在問題,比如時區的處理,還有閏年的處理上,自己實現之后使用腳本測試過一些日期和mktime對比是沒有問題的。

上代碼如下: 
代碼下載:github——str_to_stamp.c

 1 #include <stdio.h>
 2 #include <time.h>
 3 
 4 /*字符串時間(YYYYMMDD-HH:MM:mm)轉換為struct tm結構*/
 5 void str_to_tm(char *p_time, struct tm* m_tm)
 6 {
 7     if(p_time)
 8     {
 9         sscanf(p_time, "%4d%2d%2d-%d:%d:%d", &m_tm->tm_year,&m_tm->tm_mon,&m_tm->tm_mday,&m_tm->tm_hour,&m_tm->tm_min,&m_tm->tm_sec);
10         m_tm->tm_mon -= 1;
11         m_tm->tm_year -= 1900;
12     printf("%4d%2d%2d-%d:%d:%d\n", m_tm->tm_year,m_tm->tm_mon,m_tm->tm_mday,m_tm->tm_hour,m_tm->tm_min,m_tm->tm_sec);
13     }
14     else
15     {
16         printf("input time is null\n");
17         return ;
18     }
19 }
20 
21 /*時間結構轉換為時間戳*/
22 time_t time_to_stamp(const struct tm* ltm, int utc_diff)
23 {
24     const int mon_days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
25     long tyears,tdays,leap_years,utc_hrs;
26     int is_leap;
27     int i,ryear;
28     
29     //判斷閏年
30     ryear = ltm->tm_year + 1900;
31     is_leap = ((ryear%100!=0 && ryear%4==0) || (ryear%400==0) ) ? 1 : 0;
32     
33     tyears = ltm->tm_year-70;  //時間戳從1970年開始算起
34     if(ltm->tm_mon < 1 && is_leap==1 )
35     {
36         leap_years = (tyears + 2) / 4 - 1;  //1970年不是閏年,從1972年開始閏年
37                                             //閏年的月份小於1,需要減去一天
38     }
39     else
40     {
41         leap_years = (tyears + 2) / 4 ;
42     }
43     
44     tdays = 0;
45     for(i=0; i<ltm->tm_mon; ++i)
46     {
47         tdays += mon_days[i];
48     }
49     tdays += ltm->tm_mday - 1;  //減去今天
50     tdays += tyears * 365 + leap_years;
51     utc_hrs = ltm->tm_hour - utc_diff;   //如上面解釋所說,時間戳轉換北京時間需要+8,那么這里反轉需要-8
52     
53     return (tdays * 86400) + (utc_hrs * 3600) + (ltm->tm_min * 60) + ltm->tm_sec;
54 }
55 
56 int main(int argc, char **argv)
57 {
58     char *ptime = argv[1];
59     struct tm tt;
60     int ltime = 0;
61     int systime = 0;
62     str_to_tm(ptime,&tt);
63     ltime = time_to_stamp(&tt,8);
64     printf("ltime=%d\n",ltime);
65     return 0;    
66 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM