C基礎 時間業務實戰代碼

来源:http://www.cnblogs.com/life2refuel/archive/2016/07/13/5667268.html
-Advertisement-
Play Games

業務代碼中常和時間打交道, 例如時間串, 時間戳之間轉換. 當前時間是否是同一天等. 這裡就是為瞭解決這個問題.分享了這篇博文. ...


引言

  業務代碼中遇到這樣需求, 1. 二者是同一天嗎, 2. 時間戳和時間串來迴轉, 3. 其它擴展需求 等.

C寫代碼同樣需要處理這方面時間問題. 本文就是為瞭解決這個問題. 相比其它時間庫, 這裡做了一些擴展. 一般而言

一天開始時間為 00:00:00 , 這裡 可以配置一天的開始時間.

  舉一個實際用的業務例子. 暴雪游戲, 魔獸世界 或者 爐石傳說, 每次活動刷新都是以 05:00:00 開始. 

這裡說明瞭什麼呢, 可以理解為這類游戲世界里, 時間迴圈的起點就是"05:00:00". 認為是一天的開始.

同樣我們的寫的sctimeutil.h 介面中有一個配置 一天的開始時間.

當然代碼一定是跨平臺的. 首先我們看一下 sctimeutil.h 介面設計思路如下:

#ifndef _H_SCTIMEUTIL
#define _H_SCTIMEUTIL

#include <time.h>
#include <stdbool.h>

// 為Visual Studio導入一些和linux上優質思路
#if defined(_MSC_VER)

#include <Windows.h>

/*
 * 返回當前得到的時間結構體, 高仿linux上調用
 * pt    : const time_t * , 輸入的時間戳指針
 * ptm    : struct tm * , 輸出的時間結構體
 *        : 返回 ptm 值
 */
#define localtime_r(pt, ptm) localtime_s(ptm, pt), ptm

/*
 * Linux sys/time.h 中獲取時間函數在Windows上一種移植實現
 * tv    :    返回結果包含秒數和微秒數
 * tz    :    包含的時區,在window上這個變數沒有用不返回
 *         :   預設返回0
 */
extern int gettimeofday(struct timeval* tv, void* tz);

#endif


// 定義每天是開始為 0時0分0秒
#define _INT_MINSECOND        (60)
#define _INT_HOURSECOND        (3600)
#define _INT_DAYSECOND        (24UL*_INT_HOURSECOND)
#define _INT_DAYSTART        (8UL*_INT_HOURSECOND)
// 定義每天新的開始時間
#define _INT_DAYNEWSTART    (0UL*_INT_HOURSECOND + 0*_INT_MINSECOND + 0)

// struct tm 中 tm_year, tm_mon 用的偏移量
#define _INT_YEAROFFSET        (1900)
#define _INT_MONOFFSET        (1)

// 定義時間串類型
#define _INT_STULEN            (32)
typedef char stime_t[_INT_STULEN];

/*
 * 將 [2016-7-10 21:22:34] 格式字元串轉成時間戳
 * tstr    : 時間串分隔符只能是單位元組的.
 * pt    : 返回得到的時間戳
 * otm    : 返回得到的時間結構體
 *        : 返回這個字元串轉成的時間戳, -1表示構造失敗
 */
extern bool stu_gettime(stime_t tstr, time_t * pt, struct tm * otm);

/*
 * 判斷當前時間戳是否是同一天的.
 * lt : 判斷時間一
 * rt : 判斷時間二
 *    : 返回true表示是同一天, 返回false表示不是
 */
extern bool stu_tisday(time_t lt, time_t rt);

/*
 * 判斷當前時間戳是否是同一周的.
 * lt : 判斷時間一
 * rt : 判斷時間二
 *    : 返回true表示是同一周, 返回false表示不是
 */
extern bool stu_tisweek(time_t lt, time_t rt);

/*
 * 將時間戳轉成時間串 [2016-7-10 22:38:34]
 * nt    : 當前待轉的時間戳
 * tstr    : 保存的轉後時間戳位置
 *        : 返回傳入tstr的首地址
 */
extern char * stu_gettstr(time_t nt, stime_t tstr);

/*
 * 得到當前時間戳 [2016-7-10 22:38:34]
 * tstr    : 保存的轉後時間戳位置
 *        : 返回傳入tstr的首地址
 */
extern char * stu_getntstr(stime_t tstr);

/*
 * 判斷當前時間串是否是同一天的.
 * ls : 判斷時間一
 * rs : 判斷時間二
 *    : 返回true表示是同一天, 返回false表示不是
 */
extern bool stu_sisday(stime_t ls, stime_t rs);

/*
 * 判斷當前時間串是否是同一周的.
 * ls : 判斷時間一
 * rs : 判斷時間二
 *    : 返回true表示是同一周, 返回false表示不是
 */
extern bool stu_sisweek(stime_t ls, stime_t rs);

#endif // !_H_SCTIMEUTIL

設計介面瞭解後, 後面會詳細解說. (代碼對齊確實不好弄, 要是博客園直接能讓VS複製的代碼格式, 到富文本框中不改變, 那得多好.)

設計師才是王道.

 

前言

   先看巨集配置, 主要的就是

// 定義每天新的開始時間
#define _INT_DAYNEWSTART    (0UL*_INT_HOURSECOND + 0*_INT_MINSECOND + 0)

假如需要設置一天開始為05:00:00, 那就將第一個0變成5就可以了.  後面還定義了時間串類型

// 定義時間串類型
#define _INT_STULEN            (32)
typedef char stime_t[_INT_STULEN];

預設就是 char [32]長度的字元串. 統一類型在棧上並節省一個長度參數, 否則一般得到時間串 至少 char [], int 兩個參數.

其它的變數巨集, 都是為了去掉魔法數字用的.  最前面有段為VS導入擴展功能的巨集

// 為Visual Studio導入一些和linux上優質思路
#if defined(_MSC_VER)

#include <Windows.h>

/*
 * 返回當前得到的時間結構體, 高仿linux上調用
 * pt    : const time_t * , 輸入的時間戳指針
 * ptm    : struct tm * , 輸出的時間結構體
 *        : 返回 ptm 值
 */
#define localtime_r(pt, ptm) localtime_s(ptm, pt), ptm

/*
 * Linux sys/time.h 中獲取時間函數在Windows上一種移植實現
 * tv    :    返回結果包含秒數和微秒數
 * tz    :    包含的時區,在window上這個變數沒有用不返回
 *         :   預設返回0
 */
extern int gettimeofday(struct timeval* tv, void* tz);

#endif

這兩個''聲明''在跨平臺C代碼中出現頻率比較高. 第一個是安全可重入的將時間戳變成時間結構體. 第二個是得到更高精度的時間表示.

這裡分析一下對於linux上 有這麼定義

struct tm *localtime_r(const time_t *timep, struct tm *result);

window 上是下麵定義的

static __inline errno_t __CRTDECL localtime_s(struct tm * _Tm, const time_t * _Time)
{
    return _localtime32_s(_Tm, _Time);
}

簡單的理解為, 位置顛倒了. 其實而言, 細節上還是有不同. 扯一點二者平臺都有優點,

但從這個api上而言, 我覺得linux上localtime_r 更自然些, 返回值放在最後面. 隨著工作深入也發現,

有些api window設計也很出彩. 但是總的而言, 如果二選一, 還是覺得linux 設計的比window漂亮, 精妙, 自然.

扯回來, 上面為了更大程度上相容linux, 就在window上採用linux函數設計思路. 是不是有點意思.(另外一種跨平臺巨集設計思路)

對於 gettimeofday window源碼實現如下

// 為Visual Studio導入一些和linux上優質思路
#if defined(_MSC_VER)

/*
 * Linux sys/time.h 中獲取時間函數在Windows上一種移植實現
 * tv    :    返回結果包含秒數和微秒數
 * tz    :    包含的時區,在window上這個變數沒有用不返回
 *         :   預設返回0
 */
int 
gettimeofday(struct timeval* tv, void* tz) {
    struct tm st;
    SYSTEMTIME wtm;

    GetLocalTime(&wtm);
    st.tm_year = wtm.wYear - _INT_YEAROFFSET;
    st.tm_mon = wtm.wMonth - _INT_MONOFFSET; // window的計數更好些
    st.tm_mday = wtm.wDay;
    st.tm_hour = wtm.wHour;
    st.tm_min = wtm.wMinute;
    st.tm_sec = wtm.wSecond;
    st.tm_isdst = -1; // 不考慮夏令時

    tv->tv_sec = (long)mktime(&st); // 32位使用數據強轉
    tv->tv_usec = wtm.wMilliseconds * 1000; // 毫秒轉成微秒

    return 0;
}

#endif

上面兩個巨集, 分別是 1900和1, 這個是 struct tm 特性決定的, 這點window api功能設計的好.

#ifndef _TM_DEFINED
struct tm {
        int tm_sec;     /* seconds after the minute - [0,59] */
        int tm_min;     /* minutes after the hour - [0,59] */
        int tm_hour;    /* hours since midnight - [0,23] */
        int tm_mday;    /* day of the month - [1,31] */
        int tm_mon;     /* months since January - [0,11] */
        int tm_year;    /* years since 1900 */
        int tm_wday;    /* days since Sunday - [0,6] */
        int tm_yday;    /* days since January 1 - [0,365] */
        int tm_isdst;   /* daylight savings time flag */
        };
#define _TM_DEFINED
#endif

上面就是 struct tm 結構體實現. 時間操作還是比較不統一, 需要一定經驗, 多趟坑. 這裡時間預設從1900起計算, 也有1970起計算的. 例如(man 手冊中內容)

       The ctime(), gmtime() and localtime() functions all take an argument of data type time_t which represents cal‐
       endar  time.   When  interpreted  as an absolute time value, it represents the number of seconds elapsed since
       00:00:00 on January 1, 1970, Coordinated Universal Time (UTC).

需要用到的時候再弄清楚吧. 推薦一定要用可重入的, 否則程式跑起來只能頭大了.

 

正文

  現在準備剖析一下特定的代碼, 最後也會貼一下全部代碼. 運行一個測試demo. 首先看時間串得到時間戳時間結構體的介面實現

/*
 * 將 [2016-7-10 21:22:34] 格式字元串轉成時間戳
 * tstr    : 時間串分隔符只能是單位元組的.
 * pt    : 返回得到的時間戳
 * otm    : 返回得到的時間結構體
 *        : 返回這個字元串轉成的時間戳, -1表示構造失敗
 */
bool 
stu_gettime(stime_t tstr, time_t * pt, struct tm * otm) {
    time_t t;
    struct tm st;

    if(NULL == tstr)
        return false;

    int rt = sscanf(tstr, "%d%*c%d%*c%d%*c%d%*c%d%*c%d", 
                     &st.tm_year, &st.tm_mon, &st.tm_mday,
                     &st.tm_hour, &st.tm_min, &st.tm_sec);
    if(6 != rt)
        return false;
    
    st.tm_year -= _INT_YEAROFFSET;
    st.tm_mon -= _INT_MONOFFSET;
    // 得到時間戳, 失敗返回false
    if((t = mktime(&st)) == -1 )
        return false;

    // 返回最終結果
    if(pt)
        *pt = t;
    if(otm)
        *otm = st;

    return true;
}

思路很清晰, 解析時間串, 得到年月日時分秒, 最後通過mktime得到想要的. 期間需要註意的是 struct tm 必須 year 1900起, mon 從0開始記.

執行mktime之後會補充玩 st 時間結構體 並且返回當前時間戳.

判斷兩個時間戳是否是同一天也很巧妙

/*
 * 判斷當前時間戳是否是同一天的.
 * lt : 判斷時間一
 * rt : 判斷時間二
 *    : 返回true表示是同一天, 返回false表示不是
 */
bool 
stu_tisday(time_t lt, time_t rt) {
    // 得到是各自第幾天的
    lt = (lt + _INT_DAYSTART - _INT_DAYNEWSTART) / _INT_DAYSECOND;
    rt = (rt + _INT_DAYSTART - _INT_DAYNEWSTART) / _INT_DAYSECOND;
    return lt == rt;
}

這裡用到一個巨集

#define _INT_DAYSTART        (8UL*_INT_HOURSECOND)

這個由來是咱們通過mktime 得到的是 標準時區時間, 而中國是東八區, 快了它8h. 詳細科普可以看下下麵資料

GMT(Greenwich Mean Time)  格林威治時間
    即本初子午線的時間,一般作為全球時間的基準參考時間。據說是以格林威治天文臺命名的。
UTC(Universal Time Coordinated) 世界標準時間或世界協調時間 協調世界時是以原子時秒長為基礎,在時刻上儘量接近於世界時的一種時間計量系統。
UTC時間和GMT時間其實是同一個時間,只不過UTC時間的單位是秒。定期會進行校準,校準的方式是發佈閏秒,
即有兩個同樣的秒。記住,UTC是GMT的以秒為單位的計時。
CST(China Standard Time) 中國標準時間 可以認為新聞聯播嘟嘟嘟的時間。也就是東八區的時間。當GMT為0點的時候,我們已經8點了。
我們的時間需要在GMT的時間上加八個小時

有了這些知識, 後面 將兩個時間戳變成中國的時間戳. 再除以一天的秒數, 得到當前多少天了. 這裡需要註意一下, 這是伺服器級別的時間判斷.

如果對於軍工級別, 宇宙飛船等級別, 真不行, 因為一年民用要麼365要麼366, 其實一年 查了粗略資料有

地球圍繞太陽公轉一周(即360度)的時間應該為365日6時9分10秒,即為一個恆星年。

地球的某點獲得兩次兩次直射的間隔是365日5時48分46秒(更加精確:365天5小時48分45.975456秒),即為一個回歸年。

總而言之, 電腦還是離散數學級別, 精度只能大致算算, 因此咱們精度到天, 上面演算法是可以得了, 對於特別意外的那就看臉了.

(時間判斷也是程式國際化會遇到的一個坑, 必遇到滴~~)

從這裡覺得軟體開發還是偏藝術些, 科學是嚴謹的, 是符合一切數學規律的, 誤差是可以詳細分析的.

再看看另一個設計, 比較簡單, 時間戳得到時間串

/*
 * 將時間戳轉成時間串 [2016-7-10 22:38:34]
 * nt    : 當前待轉的時間戳
 * tstr    : 保存的轉後時間戳位置
 *        : 返回傳入tstr的首地址
 */
char * stu_gettstr(time_t nt, stime_t tstr) {
    struct tm st;
    localtime_r(&nt, &st);
    strftime(tstr, sizeof(stime_t), "%F %X", &st);
    return tstr;
}

思路很直白吧,最後解釋測試一波了. 首先看main.c

#include <stdio.h>
#include <stdlib.h>
#include "sctimeutil.h"

static void _sctime_puts(stime_t tstr) {
    printf("sizeof tstr = %lu, %lu\n", sizeof tstr, sizeof(stime_t));
}

/*
 * 處理時間 time 的測試主函數
 * 
 */
int main(int argc, char * argv[]) {
    bool rt;
    time_t t;
    struct tm tm;
    stime_t ts;    

    rt = stu_gettime("2016-7-12 11:27:00", &t, &tm);
    printf("tm.tm_year = %d, tm.tm_yday = %d\n", tm.tm_year, tm.tm_yday);
    
    // 測試數組長度
    _sctime_puts(NULL);

    rt = stu_sisweek("2016-7-11 20:59:59", "2016-7-17 23:59:59");
    printf("rt = %d\n", rt);

    rt = stu_sisweek("2016-7-11 0:0:0", "2016-7-18 0:0:0");
    printf("rt = %d\n", rt);
    
    // 輸出當前時間量
    puts(stu_getntstr(ts));

    return 0;
}

附加代碼文件

sctimeutil.h

#ifndef _H_SCTIMEUTIL
#define _H_SCTIMEUTIL

#include <time.h>
#include <stdbool.h>

// 為Visual Studio導入一些和linux上優質思路
#if defined(_MSC_VER)

#include <Windows.h>

/*
 * 返回當前得到的時間結構體, 高仿linux上調用
 * pt    : const time_t * , 輸入的時間戳指針
 * ptm    : struct tm * , 輸出的時間結構體
 *        : 返回 ptm 值
 */
#define localtime_r(pt, ptm) localtime_s(ptm, pt), ptm

/*
 * Linux sys/time.h 中獲取時間函數在Windows上一種移植實現
 * tv    :    返回結果包含秒數和微秒數
 * tz    :    包含的時區,在window上這個變數沒有用不返回
 *         :   預設返回0
 */
extern int gettimeofday(struct timeval* tv, void* tz);

#endif


// 定義每天是開始為 0時0分0秒
#define _INT_MINSECOND        (60)
#define _INT_HOURSECOND        (3600)
#define _INT_DAYSECOND        (24UL*_INT_HOURSECOND)
#define _INT_DAYSTART        (8UL*_INT_HOURSECOND)
// 定義每天新的開始時間
#define _INT_DAYNEWSTART    (0UL*_INT_HOURSECOND + 0*_INT_MINSECOND + 0)

// struct tm 中 tm_year, tm_mon 用的偏移量
#define _INT_YEAROFFSET        (1900)
#define _INT_MONOFFSET        (1)

// 定義時間串類型
#define _INT_STULEN            (32)
typedef char stime_t[_INT_STULEN];

/*
 * 將 [2016-7-10 21:22:34] 格式字元串轉成時間戳
 * tstr    : 時間串分隔符只能是單位元組的.
 * pt    : 返回得到的時間戳
 * otm    : 返回得到的時間結構體
 *        : 返回這個字元串轉成的時間戳, -1表示構造失敗
 */
extern bool stu_gettime(stime_t tstr, time_t * pt, struct tm * otm);

/*
 * 判斷當前時間戳是否是同一天的.
 * lt : 判斷時間一
 * rt : 判斷時間二
 *    : 返回true表示是同一天, 返回false表示不是
 */
extern bool stu_tisday(time_t lt, time_t rt);

/*
 * 判斷當前時間戳是否是同一周的.
 * lt : 判斷時間一
 * rt : 判斷時間二
 *    : 返回true表示是同一周, 返回false表示不是
 */
extern bool stu_tisweek(time_t lt, time_t rt);

/*
 * 將時間戳轉成時間串 [2016-7-10 22:38:34]
 * nt    : 當前待轉的時間戳
 * tstr    : 保存的轉後時間戳位置
 *        : 返回傳入tstr的首地址
 */
extern char * stu_gettstr(time_t nt, stime_t tstr);

/*
 * 得到當前時間戳 [2016-7-10 22:38:34]
 * tstr    : 保存的轉後時間戳位置
 *        : 返回傳入tstr的首地址
 */
extern char * stu_getntstr(stime_t tstr);

/*
 * 判斷當前時間串是否是同一天的.
 * ls : 判斷時間一
 * rs : 判斷時間二
 *    : 返回true表示是同一天, 返回false表示不是
 */
extern bool stu_sisday(stime_t ls, stime_t rs);

/*
 * 判斷當前時間串是否是同一周的.
 * ls : 判斷時間一
 * rs : 判斷時間二
 *    : 返回true表示是同一周, 返回false表示不是
 */
extern bool stu_sisweek(stime_t ls, stime_t rs);

#endif // !_H_SCTIMEUTIL
View Code

sctimeutil.c

#include "sctimeutil.h"
#include <stdio.h>

// 為Visual Studio導入一些和linux上優質思路
#if defined(_MSC_VER)

/*
 * Linux sys/time.h 中獲取時間函數在Windows上一種移植實現
 * tv    :    返回結果包含秒數和微秒數
 * tz    :    包含的時區,在window上這個變數沒有用不返回
 *         :   預設返回0
 */
int 
gettimeofday(struct timeval* tv, void* tz) {
    struct tm st;
    SYSTEMTIME wtm;

    GetLocalTime(&wtm);
    st.tm_year = wtm.wYear - _INT_YEAROFFSET;
    st.tm_mon = wtm.wMonth - _INT_MONOFFSET; // window的計數更好些
    st.tm_mday = wtm.wDay;
    st.tm_hour = wtm.wHour;
    st.tm_min = wtm.wMinute;
    st.tm_sec = wtm.wSecond;
    st.tm_isdst = -1; // 不考慮夏令時

    tv->tv_sec = (long)mktime(&st); // 32位使用數據強轉
    tv->tv_usec = wtm.wMilliseconds * 1000; // 毫秒轉成微秒

    return 0;
}

#endif

/*
 * 將 [2016-7-10 21:22:34] 格式字元串轉成時間戳
 * tstr    : 時間串分隔符只能是單位元組的.
 * pt    : 返回得到的時間戳
 * otm    : 返回得到的時間結構體
 *        : 返回這個字元串轉成的時間戳, -1表示構造失敗
 */
bool 
stu_gettime(stime_t tstr, time_t * pt, struct tm * otm) {
    time_t t;
    struct tm st;

    if(NULL == tstr)
        return false;

    int rt = sscanf(tstr, "%d%*c%d%*c%d%*c%d%*c%d%*c%d", 
                     &st.tm_year, &st.tm_mon, &st.tm_mday,
                     &st.tm_hour, &st.tm_min, &st.tm_sec);
    if(6 != rt)
        return false;
    
    st.tm_year -= _INT_YEAROFFSET;
    st.tm_mon -= _INT_MONOFFSET;
    // 得到時間戳, 失敗返回false
    if((t = mktime(&st)) == -1 )
        return false;

    // 返回最終結果
    if(pt)
        *pt = t;
    if(otm)
        *otm = st;

    return true;
}

/*
 * 判斷當前時間戳是否是同一天的.
 * lt : 判斷時間一
 * rt : 判斷時間二
 *    : 返回true表示是同一天, 返回false表示不是
 */
bool 
stu_tisday(time_t lt, time_t rt) {
    // 得到是各自第幾天的
    lt = (lt + _INT_DAYSTART - _INT_DAYNEWSTART) / _INT_DAYSECOND;
    rt = (rt + _INT_DAYSTART - _INT_DAYNEWSTART) / _INT_DAYSECOND;
    return lt == rt;
}

/*
 * 判斷當前時間戳是否是同一周的.
 * lt : 判斷時間一
 * rt : 判斷時間二
 *    : 返回true表示是同一周, 返回false表示不是
 */
bool 
stu_tisweek(time_t lt, time_t rt) {
    time_t mt;
    struct tm st;
    
    lt -= _INT_DAYNEWSTART;
    rt -= _INT_DAYNEWSTART;
    
    if(lt < rt) { //得到最大時間, 保存在lt中
        mt = lt;
        lt = rt;
        rt = mt;
    }
    
    // 得到lt 表示的當前時間
    localtime_r(&lt, &st);
    
    // 得到當前時間到周一起點的時間差
    st.tm_wday = 0 == st.tm_wday ? 7 : st.tm_wday;
    mt = (st.tm_wday - 1) * _INT_DAYSECOND + st.tm_hour * _INT_HOURSECOND
        + st.tm_min * _INT_MINSECOND + st.tm_sec;

    // [min, lt], lt = max(lt, rt) 就表示在同一周內
    return rt >= lt - mt;
}

/*
 * 將時間戳轉成時間串 [2016-7-10 22:38:34]
 * nt    : 當前待轉的時間戳
 * tstr    : 保存的轉後時間戳位置
 *        : 返回傳入tstr的首地址
 */
char * stu_gettstr(time_t nt, stime_t tstr) {
    struct tm st;
    localtime_r(&nt, &st);
    strftime(tstr, sizeof(stime_t), "%F %X", &st);
    return tstr;
}

/*
 * 得到當前時間戳 [2016-7-10 22:38:34]
 * tstr    : 保存的轉後時間戳位置
 *        : 返回傳入tstr的首地址
 */
char * stu_getntstr(stime_t tstr) {
    return stu_gettstr(time(NULL), tstr);
}

/*
 * 判斷當前時間串是否是同一天的.
 * ls : 判斷時間一
 * rs : 判斷時間二
 *    : 返回true表示是同一天, 返回false表示不是
 */
bool 
stu_sisday(stime_t ls, stime_t rs) {
    time_t lt, rt;
    // 解析失敗直接返回結果
    if(!stu_gettime(ls, &lt, NULL) || !stu_gettime(rs, &rt, NULL))
        return false;

    return stu_tisday(lt, rt);
}

/*
 * 判斷當前時間串是否是同一周的.可以優化
 * ls : 判斷時間一
 * rs : 判斷時間二
 *    : 返回true表示是同一周, 返回false表示不是
 */
bool 
stu_sisweek(stime_t ls, stime_t rs) {
    time_t lt, rt;
    // 解析失敗直接返回結果
    if(!stu_gettime(ls, &lt, NULL) || !stu_gettime(rs, &rt, NULL))
        return false;

    return stu_tisweek(lt, rt);
}
View Code

 

編譯命令

gcc -Wall -ggdb2 -o main.out main.c sctimeutil.c

測試結果 達到預期

window上測試也一樣. 有興趣的可以將思路用在自己的項目中. 思路比代碼有底蘊. 軟體開發, 馬龍還是無法簡單的表達咱們職業的.

設計師覺得更貼切些. 用雙手描繪色彩務實的人們.

 

後記

  錯誤是難免的, 歡迎吐槽, 再打補丁修複~~

 

附加 :

   晚上將代碼加入simplec框架中, 創造了更有意思的代碼, 真心值得學習研究 . 萬能時間轉換函數. 性能也好了許多. 拋棄了sscanf 這種大塊頭函數.

// 從時間串中提取出來年月日時分秒
static bool _stu_gettm(stime_t tstr, struct tm * otm) {
    int * py, * es;
    char c;
    int sum;

    if ((!tstr) || !(c = *tstr) || c < '0' || c > '9')
        return false;

    py = &otm->tm_year;
    es = &otm->tm_sec;
    sum = 0;
    while ((c = *tstr) && py >= es) {
        if (c >= '0' && c <= '9') {
            sum = 10 * sum + c - '0';
            ++tstr;
            continue;
        }

        *py-- = sum;
        sum = 0;

        // 去掉特殊字元, 一直找到下一個數字
        while ((c = *++tstr) && (c<'0' || c>'9'))
            ;
    }
    // 非法, 最後解析出錯
    if (py != es)
        return false;

    *es = sum; // 保存最後秒數據
    return true;
}

/*
 * 將 [2016-7-10 21:22:34] 格式字元串轉成時間戳
 * tstr    : 時間串分隔符只能是單位元組的.
 * pt    : 返回得到的時間戳
 * otm    : 返回得到的時間結構體
 *        : 返回這個字元串轉成的時間戳, -1表示構造失敗
 */
bool
stu_gettime(stime_t tstr, time_t * pt, struct tm * otm) {
    time_t t;
    struct tm st;

    // 先解析年月日時分秒
    if (!_stu_gettm(tstr, &st))
        return false;

    st.tm_year -= _INT_YEAROFFSET;
    st.tm_mon -= _INT_MONOFFSET;
    // 得到時間戳, 失敗返回false
    if ((t = mktime(&st)) == -1)
        return false;

    // 返回最終結果
    if (pt)
        *pt = t;
    if (otm)
        *otm = st;

    return true;
}

 

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 重寫模板查找方式: Application_Start()註冊 _ViewStart.cshtml @{ Layout = "~/Views/Shared/_Layout.cshtml".Replace("~/Views/", MyRazorViewEngine.GetView(Request)); ...
  • 完美的.net真泛型真的完美嗎 碼C#多年,不求甚解覺得泛型就是傳說中那麼完美,性能也是超級好,不錯,在絕大部分場景下泛型表現簡直可以用完美來形容,不過隨著前一陣重做IOC時,才發現與自己預想中不一樣,覺得自己還是圖樣圖森破,太過拿衣服了 在前面一篇文章(一步一步造個IoC輪子(二),詳解泛型工廠) ...
  • cocos2dx版本為3.10 1.在使用spine的過程中,發現了一個比較嚴重的問題:每次創建SkeletonAnimation的時候都會很卡,即使是使用同一個骨骼數據skeletonData。 跟蹤代碼發現,在每次調用函數spine::SkeletonAnimation::createWithF ...
  • 在實戰中學習Spring,本系列的最終目的是完成一個實現用戶註冊登錄功能的項目。 預想的基本流程如下: 1、用戶網站註冊,填寫用戶名、密碼、email、手機號信息,後臺存入資料庫後返回ok。(學習IOC,mybatis,SpringMVC的基礎知識,表單數據驗證,文件上傳等) 2、伺服器非同步發送郵件 ...
  • 今天實現了一個登錄功能的Struts2小程式。 期間遇到了許多問題,記憶猶新的是 (1)新版本的tomcat9和eclipse Neon Release (4.6.0) 發生了衝突,啟動伺服器的時候老是有警告,但是又找不到問題,不得已回滾到了以前的tomcat8,沒想到竟然好了!好了?這時候心裡真特 ...
  • 想學習爬蟲,又想瞭解python語言,有個python高手推薦我看看scrapy。 scrapy是一個python爬蟲框架,據說很靈活,網上介紹該框架的信息很多,此處不再贅述。專心記錄我自己遇到的問題以及解決方案吧。 給幾個鏈接吧,我是根據這幾個東西來嘗試學習的: scrapy中文文檔(0.24版, ...
  • 轉自:http://www.cnblogs.com/colincode/archive/2011/03/30/1999604.html 1.FastReport中如果訪問報表中的對象?可以使用FindObject方法。TfrxMemoView(frxReport1.FindObject(’memo1 ...
  • Java 淺析三大特性之一多態 之前我們的文章講了Java的封裝和繼承,封裝講的時候,並沒有體現出來封裝的強大之處,反而還要慎用封裝。因為這時的封裝還沒有和多態聯繫到一起,還無法看出向上轉型的厲害之處。 多態,是指同一個行為具有多種的表現形式。同一個方法根據調用對象的不同而產生多種結果。對於Java ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...