C++實例:日期時間字符串的解析類

字號:

一個日期時間類,飛鴿傳書可以完成:
    1. 從一個給定的日期時間字符串中解析出日期時間信息
    2. 提供一些常用的日期時間的校驗算法
    該類支持的日期時間格式如下:
    5(五秒)
    4:5(四分五秒)
    5:3:6(五時三分六秒)(注:不是五小時,而是凌晨五時,絕對時間)
    2-28(2月28日)
    2-28 5:3:6(2月28日)
    2008-2-28(2008年2月28日)
    2008-2-28 17:3:6(2008年2月28日17時3分6秒)
    還支持站位符方式:
    -2- 僅設定月份為2月,其余日期采用當前值
    2008-- 僅設定年
    :23: 僅設定分
    -- :: 全部省略,采用當前日期時間作為默認值
    如果不能解析到指定的部分,則采用默認值(默認值為當前日期)
    頭文件:
    /*
    類名:TDateTime
    描述:日期時間類
    作用:1. 從一個給定的日期時間字符串中解析出日期時間信息
    2. 提供一些常用的日期時間的校驗算法
    備注:
    該類支持的日期時間格式如下:
    5(五秒)
    4:5(四分五秒)
    5:3:6(五時三分六秒)(注:不是五小時,而是凌晨五時,絕對時間)
    2-28(2月28日)
    2-28 5:3:6(2月28日)
    2008-2-28(2008年2月28日)
    2008-2-28 17:3:6(2008年2月28日17時3分6秒)
    還支持站位符方式:
    -2- 僅設定月份為2月,其余日期采用當前值
    2008-- 僅設定年
    :23: 僅設定分
    -- :: 全部省略,采用當前日期時間作為默認值
    如果不能解析到指定的部分,則采用默認值(默認值為當前日期)
    歷史:
    2008-11-21 尹曙光(kevdmx@sina.com) 創(chuàng)建
    */
    #ifndef _TDATETIME_H_20081121_
    #define _TDATETIME_H_20081121_
    //在windows下,如果強制使用32位的time_t,請定義以下宏:
    //#ifndef _USE_32BIT_TIME_T
    //#define _USE_32BIT_TIME_T
    //#endif
    #include
    #ifndef BOOL
    #define BOOL int
    #endif
    #ifndef TRUE
    #define TRUE 1
    #endif
    #ifndef FALSE
    #define FALSE 0
    #endif
    class TDateTime
    {
    public:
    //年
    unsigned short sYear;
    //月
    unsigned char sMonth;
    //日
    unsigned char sDay;
    //時
    unsigned char sHour;
    //分
    unsigned char sMinute;
    //秒
    unsigned char sSecond;
    public:
    //構(gòu)造函數(shù),采用當前的日期時間作為默認值
    TDateTime();
    //構(gòu)造函數(shù),從time_t類型的變量中取得日期時間
    TDateTime(time_t t);
    //從字符串中解析出日期時間,未解析到的部分,采用當前默認值
    BOOL ParseDateTimeString(char *szDateTime);
    //重新為當前的日期時間
    BOOL LoadCurrentDateTime();
    //轉(zhuǎn)化為UNIX形式的time_t時間日期類型
    time_t ToUnixDatetime();
    //重新設定為有time_t類型變量指定的日期時間值
    void FromUnixDatetime(time_t t);
    //校驗當前對象的日期時間數(shù)據(jù)是否正確
    BOOL Validate();
    //校驗一個TDateTime類型變量的日期時間數(shù)據(jù)是否正確
    static BOOL Validate(TDateTime *obDateTime);
    //檢查年份是否是閏年
    static BOOL IsLeapYear(int year);
    //校驗給定的年份是否正確
    static BOOL ValidateDate(int year);
    //校驗給定的年份和月分是否正確
    static BOOL ValidateDate(int year,int month);
    //取得給定的年份,給定的月份含有的天數(shù)
    static int GetDaysOfMonth(int year, int month);
    //校驗給定的年月日數(shù)據(jù)是否正確
    static BOOL ValidateDate(int year, int month, int day);
    //檢驗給定的小時數(shù)據(jù),是否正確
    static BOOL ValidateTime(int hour);
    //校驗給定的小時分鐘數(shù)據(jù)是否正確
    static BOOL ValidateTime(int hour,int minute);
    //校驗給定的時間數(shù)據(jù)是否正確
    static BOOL ValidateTime(int hour, int minute, int second);
    //校驗給定的日期時間數(shù)據(jù)是否正確
    static BOOL ValidateDateTime(int year, int month, int day,
    int hour, int minute, int second);
    private:
    //token類型定義
    typedef enum TokenType
    {
    TT_Null 0,
    TT_Number 1,
    TT_Minus 2,
    TT_Colon 4,
    TT_Blank 8
    };
    //日期時間類型定義
    typedef enum TimePart
    {
    TP_Second 1,
    TP_Minute 2,
    TP_Hour 4,
    TP_Day 8,
    TP_Month 16,
    TP_Year 32
    };
    private:
    //將當前對象變量清零
    void ZeroDateTime(void);
    //根據(jù)字符取得該字符所屬的類型
    TDateTime::TokenType GetTokenType(char c);
    };
    #endif //#ifndef _TDATETIME_H_20081121_
    代碼文件:
    #include "stdafx.h"
    #include
    #include
    #include "tdatetime.h"
    //中國的時間區(qū)域為格林威治的東八區(qū),故需要一個時間偏移量
    const int TIMEZONE_8 8*60*60;
    TDateTime::TDateTime()
    {
    LoadCurrentDateTime();
    }
    TDateTime::TDateTime(time_t t)
    {
    FromUnixDatetime(t);
    }
    TDateTime::TokenType
    TDateTime::GetTokenType(char c)
    {
    if ((c>'0') && (c<'9'))
    return TT_Number;
    else if ('-'c){
    return TT_Minus;
    }else if ('/'c){
    return TT_Minus;
    }else if (' ' c){
    return TT_Blank;
    }else if(':'c){
    return TT_Colon;
    }else{
    return TT_Null;
    }
    }
    BOOL
    TDateTime::ParseDateTimeString(char *szDateTime)
    {
    int len strlen(szDateTime) - 1;
    TimePart timePart TP_Second;
    int pw 1;//加權(quán)
    signed short year-1;
    signed char month-1,day-1,hour-1,minute-1,second-1;  //過濾尾部空格
    while((len>0) && (' ' szDateTime[len]))
    len--;
    if (len<0) return FALSE;
    while(len>0){
    char c szDateTime[len];
    switch( GetTokenType(c))
    {
    case TT_Null: goto ParseDateTimeString_FALSE;
    case TT_Number:
    switch(timePart)
    {
    case TP_Second:
    if (second<0 )
    second c-'0';
    else
    second + (c-'0') * pw;
    pw * 10;
    break;
    case TP_Minute:
    if (minute<0 )
    minute c-'0';
    else
    minute + (c-'0') * pw;
    pw * 10;
    break;
    case TP_Hour:
    if (hour<0 )
    hour c-'0';
    else
    hour + (c-'0') * pw;
    pw * 10;
    break;
    case TP_Day:
    if (day<0 )
    day c-'0';
    else
    day + (c-'0') * pw;
    pw * 10;
    break;
    case TP_Month:
    if (month<0 )
    month c-'0';
    else
    month + (c-'0') * pw;
    pw * 10;
    break;
    case TP_Year:
    if (year<0 )
    year c-'0';
    else
    year + (c-'0') * pw;
    pw * 10;
    break;
    default:
    return FALSE;
    }
    break;
    case TT_Minus:
    switch(timePart)
    {
    case TP_Second: //如果沒有給定時間信息,則跳過,直接升級到日期
    pw 1;
    timePart TP_Month; //提升
    day second;
    second -1; //將解析到的秒信息改為日期信息
    break;
    case TP_Minute: goto ParseDateTimeString_FALSE;
    case TP_Hour: goto ParseDateTimeString_FALSE;
    case TP_Day:
    pw 1;
    timePart TP_Month; //提升
    break;
    case TP_Month:
    pw 1;
    timePart TP_Year; //提升
    break;
    case TP_Year: goto ParseDateTimeString_FALSE;
    default: goto ParseDateTimeString_FALSE;
    }
    break;
    case TT_Colon:
    switch(timePart)
    {
    case TP_Second:
    pw 1;
    timePart TP_Minute; //提升
    break;
    case TP_Minute:
    pw 1;
    timePart TP_Hour; //提升
    break;
    case TP_Hour: goto ParseDateTimeString_FALSE;
    case TP_Day: goto ParseDateTimeString_FALSE;
    case TP_Month: goto ParseDateTimeString_FALSE;
    case TP_Year: goto ParseDateTimeString_FALSE;
    default: goto ParseDateTimeString_FALSE;
    }
    break;
    case TT_Blank:
    if (TP_Hour timePart){
    timePart TP_Day; //提升
    pw 1;
    }else if (TP_Year timePart){ //前導空格
    goto ParseDateTimeString_OK;//認為結(jié)束
    }else{//在其他部分不能出現(xiàn)空格
    goto ParseDateTimeString_FALSE;
    }
    break;
    }
    len -- ;
    }
    ParseDateTimeString_OK:
    if (year>0)
    sYear year;
    if (month>0)
    sMonth month;
    if (day>0)
    sDay day;
    if (hour>0)
    sHour hour;
    if (minute>0)
    sMinute minute;
    if (second>0)
    sSecond second;
    if (Validate()){
    return TRUE;
    }else{
    ZeroDateTime();
    return FALSE;
    }
    ParseDateTimeString_FALSE:
    ZeroDateTime();
    return FALSE;
    }
    BOOL
    TDateTime::LoadCurrentDateTime()
    {
    time_t t;
    time(&t);
    FromUnixDatetime(t);
    return TRUE;
    }
    void
    TDateTime::FromUnixDatetime(time_t t)
    {
    t + TIMEZONE_8;
    struct tm *tt gmtime( &t);
    sYear tt->tm_year+1900;
    sMonth tt->tm_mon+1;
    sDay tt->tm_mday;
    sHour tt->tm_hour;
    sMinute tt->tm_min;
    sSecond tt->tm_sec;
    //free(tt);
    }
    void
    TDateTime::ZeroDateTime(void)
    {
    sYear 0;
    sMonth 0;
    sDay 0;
    sHour 0;
    sMinute 0;
    sSecond 0;
    }
    ///
    /// 判定給定的年份是否是潤年
    ///

    /// 需要判定的年份
    /// true:給定的年份是潤年。false:給定的年份不是潤年。BOOL
    TDateTime::IsLeapYear(int year)
    {
    return ((year % 4 0) && (year % 100 ! 0) || (year % 400 0));
    }
    ///
    /// 判定給定的年份是否有效。
    ///

    /// 給定的年份
    /// true:有效,false:無效
    BOOL
    TDateTime::ValidateDate(int year)
    {
    return (year > 0) && (year < 9999);
    }
    ///
    /// 判定給定的年月是否有效
    ///

    /// 給定的年份
    /// 給定的月份
    /// true:有效。false:無效。
    BOOL
    TDateTime::ValidateDate(int year,int month)
    {
    if (!ValidateDate(year))
    return FALSE;
    return (month > 0) && (month < 13);
    }
    ///
    /// 得到一個月份的天數(shù)
    ///

    ///
    ///
    /// 返回該年該月的總天數(shù),如果給定的參數(shù)有錯誤,則返回0
    int
    TDateTime::GetDaysOfMonth(int year, int month)
    {
    if (!ValidateDate(year, month))
    {
    return 0;
    }
    if (month 4 || month 6 || month 9 || month 11)
    {
    return 30;
    }
    else if (month 1 || month 3 || month 5
    || month 7 || month 8 || month 10 || month 12)
    {
    return 31;
    }
    else if (2 month)
    {
    if (IsLeapYear(year))//如果是閏年
    {
    return 29;
    }
    else
    {
    return 28;
    }
    }
    return 0;
    }
    ///
    /// 判定給定的年月日是否是一個有效的日期
    ///

    /// 給定的年份
    /// 給定的月份
    /// 給定的日子
    /// true:給定的年月日是一個有效的日期。false:不是一個有效的日期。
    BOOL
    TDateTime::ValidateDate(int year, int month, int day)
    {
    if (!ValidateDate(year, month))
    return FALSE;
    if ((day < 1) || (day > GetDaysOfMonth(year, month)))
    return FALSE;
    return TRUE;
    }
    ///
    /// 判定給定的小事是否有效
    ///

    /// 給定的小時
    /// true:有效;false:無效
    BOOL
    TDateTime::ValidateTime(int hour)
    {
    return (hour > 0) && (hour < 24);
    }
    ///
    /// 判定給定的小時和分鐘是否有效。
    ///

    /// 給定的小時
    /// 給定的分鐘
    /// true:有效;false:無效
    BOOL
    TDateTime::ValidateTime(int hour,int minute)
    {
    if (!ValidateTime(hour))
    return FALSE;
    return (minute > 0) && (minute < 60);
    }
    ///
    /// 判定給定的小時、分鐘、秒時否有效
    ///

    /// 給定的小時
    /// 給定的分鐘
    /// 給定的秒
    /// true:有效;false:無效
    BOOL
    TDateTime::ValidateTime(int hour, int minute, int second)
    {
    if (!ValidateTime(hour,minute))
    return FALSE;
    return (second > 0) && (second < 60);
    }
    ///
    /// 判定給定的年月日時分秒是否是一個有效的日期時間
    ///

    /// 給定的年份
    /// 給定的月份
    /// 給定的日子
    /// 給定的小時
    /// 給定的分鐘
    /// 給定的秒
    /// true:有效;false:無效
    BOOL
    TDateTime::ValidateDateTime(int year, int month, int day,
    int hour, int minute, int second)
    {
    return ValidateDate(year, month, day)
    && ValidateTime(hour, minute, second);
    }
    BOOL
    TDateTime::Validate()
    {
    return Validate(this);
    }
    BOOL
    TDateTime::Validate(TDateTime *obDateTime)
    {
    return ValidateDateTime(obDateTime->sYear,obDateTime->sMonth, obDateTime->sDay,
    obDateTime->sHour, obDateTime->sMinute, obDateTime->sSecond);
    }
    time_t
    TDateTime::ToUnixDatetime()
    {
    tm tt;
    tt.tm_year sYear - 1900;
    tt.tm_mon sMonth -1;
    tt.tm_mday sDay;
    tt.tm_hour sHour;
    tt.tm_min sMinute;
    tt.tm_sec sSecond;
    return mktime(&tt);
    }
    測試工程文件:
    // parsedt.cpp : 定義控制臺應用程序的入口點。
    //
    #include "stdafx.h"
    #include "tdatetime.h"
    //注意:在給定參數(shù)時,日期和時間中間有空格分隔,故需要有引號限定
    //如:exe "2008-11-21 22:23:59"
    //在UNIX下可以使用“\”進行轉(zhuǎn)義
    //如:exe 2008-11-21\ 22:23:59
    int main(int argc, char** argv)
    {
    TDateTime dtm;
    if (argc<2){
    printf("parsedt datetime_string");
    return 1;
    }
    if (!dtm.ParseDateTimeString(argv[1])){
    printf("Error!\n");
    return 1;
    }
    printf("year:%d, month:%d, day:%d, hour:%d, minute:%d, second:%d\n",
    dtm.sYear, dtm.sMonth, dtm.sDay, dtm.sHour, dtm.sMinute, dtm.sSecond);
    TDateTime dtm2(dtm.ToUnixDatetime());
    printf("year:%d, month:%d, day:%d, hour:%d, minute:%d, second:%d\n",
    dtm2.sYear, dtm2.sMonth, dtm2.sDay, dtm2.sHour, dtm2.sMinute, dtm2.sSecond);
    return 0;
    }
    VS2005下編譯通過。該代碼沒有平臺相關性,可以在UNIX下編譯。