一个日期时间字符串的解析类

一个日期时间类,可以完成:
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)  创建
*/

#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~~
尹曙光
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值