一個日期時間字符串的解析類

一個日期時間類,可以完成:
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     尹曙光([email protected])  創建
*/

#ifndef _TDATETIME_H_20081121_
#define _TDATETIME_H_20081121_

//在windows下,如果強制使用32位的time_t,請定義以下宏:
//#ifndef _USE_32BIT_TIME_T
//#define _USE_32BIT_TIME_T
//#endif
#include <time.h>

#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:
    //構造函數,採用當前的日期時間作爲默認值
    TDateTime();
    //構造函數,從time_t類型的變量中取得日期時間
    TDateTime(time_t t);
    //從字符串中解析出日期時間,未解析到的部分,採用當前默認值
    BOOL ParseDateTimeString(char *szDateTime);
    //重新爲當前的日期時間
    BOOL LoadCurrentDateTime();
    //轉化爲UNIX形式的time_t時間日期類型
    time_t ToUnixDatetime();
    //重新設定爲有time_t類型變量指定的日期時間值
    void FromUnixDatetime(time_t t);
    //校驗當前對象的日期時間數據是否正確
    BOOL Validate();
    //校驗一個TDateTime類型變量的日期時間數據是否正確
    static BOOL Validate(TDateTime *obDateTime);
    //檢查年份是否是閏年
    static BOOL IsLeapYear(int year);
    //校驗給定的年份是否正確
    static BOOL ValidateDate(int year);
    //校驗給定的年份和月分是否正確
    static BOOL ValidateDate(int year,int month);
    //取得給定的年份,給定的月份含有的天數
    static int GetDaysOfMonth(int year, int month);
    //校驗給定的年月日數據是否正確
    static BOOL ValidateDate(int year, int month, int day);
    //檢驗給定的小時數據,是否正確
    static BOOL ValidateTime(int hour);
    //校驗給定的小時分鐘數據是否正確
    static BOOL ValidateTime(int hour,int minute);
    //校驗給定的時間數據是否正確
    static BOOL ValidateTime(int hour, int minute, int second);
    //校驗給定的日期時間數據是否正確
    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);
    //根據字符取得該字符所屬的類型
    TDateTime::TokenType GetTokenType(char c);
};

#endif  //#ifndef _TDATETIME_H_20081121_


代碼文件:
==================================================================

#include "stdafx.h"
#include <stdlib.h>
#include <string.h>
#include "tdatetime.h"

//中國的時間區域爲格林威治的東八區,故需要一個時間偏移量
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;//加權
    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;//認爲結束               
            }else{//在其他部分不能出現空格
                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;
}


/// <summary>
/// 判定給定的年份是否是潤年
/// </summary>
/// <param name="year">需要判定的年份</param>
/// <returns>true:給定的年份是潤年。false:給定的年份不是潤年。</returns>
BOOL
TDateTime::IsLeapYear(int year)
{
    return ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0));                              
}

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

/// <summary>
/// 判定給定的年月是否有效
/// </summary>
/// <param name="year">給定的年份</param>
/// <param name="month">給定的月份</param>
/// <returns>true:有效。false:無效。</returns>
BOOL
TDateTime::ValidateDate(int year,int month)
{
    if (!ValidateDate(year))
        return FALSE;
    return (month > 0) && (month < 13);
}

/// <summary>
/// 得到一個月份的天數
/// </summary>
/// <param name="year">年</param>
/// <param name="month">月</param>
/// <returns>返回該年該月的總天數,如果給定的參數有錯誤,則返回0</returns>
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;
}

/// <summary>
/// 判定給定的年月日是否是一個有效的日期
/// </summary>
/// <param name="year">給定的年份</param>
/// <param name="month">給定的月份</param>
/// <param name="day">給定的日子</param>
/// <returns>true:給定的年月日是一個有效的日期。false:不是一個有效的日期。</returns>
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;                       
}

/// <summary>
/// 判定給定的小事是否有效
/// </summary>
/// <param name="hour">給定的小時</param>
/// <returns>true:有效;false:無效</returns>
BOOL
TDateTime::ValidateTime(int hour)
{
    return (hour >= 0) && (hour < 24);
}

/// <summary>
/// 判定給定的小時和分鐘是否有效。
/// </summary>
/// <param name="hour">給定的小時</param>
/// <param name="minute">給定的分鐘</param>
/// <returns>true:有效;false:無效</returns>
BOOL
TDateTime::ValidateTime(int hour,int minute)
{
    if (!ValidateTime(hour))
        return FALSE;
    return (minute >= 0) && (minute < 60);
}

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

/// <summary>
/// 判定給定的年月日時分秒是否是一個有效的日期時間
/// </summary>
/// <param name="year">給定的年份</param>
/// <param name="month">給定的月份</param>
/// <param name="day">給定的日子</param>
/// <param name="hour">給定的小時</param>
/// <param name="minute">給定的分鐘</param>
/// <param name="second">給定的秒</param>
/// <returns>true:有效;false:無效</returns>
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"

//注意:在給定參數時,日期和時間中間有空格分隔,故需要有引號限定
//如:exe "2008-11-21 22:23:59"
//在UNIX下可以使用“\”進行轉義
//如: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下編譯。

~~THE END~~
尹曙光
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章