rdate, 時間格式化,在unix系統實現類似linux系統的date命令

raysuen發表於2017-10-21



#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <ctype.h>

#include <time.h>

#include <math.h>


void Func_help()  //幫助函式

{

    printf("NAME:\n");

    printf("    rdate  --display date and time\n");

    printf("SYNOPSIS:\n");

    printf("    rdate [-f] [time format] [-c] [colculation format] \n");

    printf("DESCRIPTION:\n");

    printf("    \n");

    printf("    -c: value is day/month/year,plus +/-,plus a number which is number to colculate\n");

    printf("    \n");

    printf("    -f:\n");

    printf("    \n");

    printf("     %%A    is replaced by national representation of the full weekday name.\n");

    printf("     %%a    is replaced by national representation of the abbreviated weekday name.\n");

    printf("     %%B    is replaced by national representation of the full month name.\n");

    printf("     %%b    is replaced by national representation of the abbreviated month name.\n");

    printf("     %%C    is replaced by (year / 100) as decimal number; single digits are preceded by a zero.\n");

    printf("     %%c    is replaced by national representation of time and date.\n");

    printf("     %%D    is equivalent to ``%%m/%%d/%%y''.\n");

    printf("     %%d    is replaced by the day of the month as a decimal number (01-31).\n");

    printf("     %%E* %%O*\n");

    printf("            POSIX locale extensions.  The sequences %%Ec %%EC %%Ex %%EX %%Ey %%EY %%Od %%Oe %%OH %%OI %%Om %%OM %%OS %%Ou %%OU %%OV %%Ow %%OW %%Oy are supposed to provide alternate\n");

    printf("            representations.\n");

    printf("            Additionally %%OB implemented to represent alternative months names (used standalone, without day mentioned).\n");

    printf("     %%e    is replaced by the day of the month as a decimal number (1-31); single digits are preceded by a blank.\n");

    printf("     %%F    is equivalent to ``%%Y-%%m-%%d''.\n");

    printf("     %%G    is replaced by a year as a decimal number with century.  This year is the one that contains the greater part of the week (Monday as the first day of\n");

    printf("            the week).\n");

    printf("     %%g    is replaced by the same year as in ``%%G'', but as a decimal number without century (00-99).\n");

    printf("     %%H    is replaced by the hour (24-hour clock) as a decimal number (00-23).\n");

    printf("     %%h    the same as %%b.\n");

    printf("     %%I    is replaced by the hour (12-hour clock) as a decimal number (01-12).\n");

    printf("     %%j    is replaced by the day of the year as a decimal number (001-366).\n");

    printf("     %%k    is replaced by the hour (24-hour clock) as a decimal number (0-23); single digits are preceded by a blank.\n");

    printf("     %%l    is replaced by the hour (12-hour clock) as a decimal number (1-12); single digits are preceded by a blank.\n");

    printf("     %%M    is replaced by the minute as a decimal number (00-59).\n");

    printf("     %%m    is replaced by the month as a decimal number (01-12).\n");

    printf("     %%n    is replaced by a newline.\n");

    printf("     %%O*   the same as %%E*.\n");

    printf("     %%p    is replaced by national representation of either ante meridiem (a.m.)  or post meridiem (p.m.)  as appropriate.\n");

    printf("     %%R    is equivalent to ``%%H:%%M''.\n");

    printf("     %%r    is equivalent to ``%%I:%%M:%%S %%p''.\n");

    printf("     %%S    is replaced by the second as a decimal number (00-60).\n");

    printf("     %%s    is replaced by the number of seconds since the Epoch, UTC (see mktime(3)).\n");

    printf("     %%T    is equivalent to ``%%H:%%M:%%S''.\n");

    printf("     %%t    is replaced by a tab.\n");

    printf("     %%U    is replaced by the week number of the year (Sunday as the first day of the week) as a decimal number (00-53).\n");

    printf("     %%u    is replaced by the weekday (Monday as the first day of the week) as a decimal number (1-7).\n");

    printf("     %%V    is replaced by the week number of the year (Monday as the first day of the week) as a decimal number (01-53).  If the week containing January 1 has\n");

    printf("            four or more days in the new year, then it is week 1; otherwise it is the last week of the previous year, and the next week is week 1.\n");

    printf("     %%v    is equivalent to ``%%e-%%b-%%Y''.\n");

    printf("     %%W    is replaced by the week number of the year (Monday as the first day of the week) as a decimal number (00-53).\n");

    printf("     %%w    is replaced by the weekday (Sunday as the first day of the week) as a decimal number (0-6).\n");

    printf("     %%X    is replaced by national representation of the time.\n");

    printf("     %%x    is replaced by national representation of the date.\n");

    printf("     %%Y    is replaced by the year with century as a decimal number.\n");

    printf("     %%y    is replaced by the year without century as a decimal number (00-99).\n");

    printf("     %%Z    is replaced by the time zone name.\n");

    printf("     %%z    is replaced by the time zone offset from UTC; a leading plus sign stands for east of UTC, a minus sign for west of UTC, hours and minutes follow with\n");

    printf("            two digits each and no delimiter between them (common form for RFC 822 date headers).\n");

    printf("     %%+    is replaced by national representation of the date and time (the format is similar to that produced by date(1)).\n");

    printf("     %%-*   GNU libc extension.  Do not do any padding when performing numerical outputs.\n");

    printf("     %%_*   GNU libc extension.  Explicitly specify space for padding.\n");

    printf("     %%0*   GNU libc extension.  Explicitly specify zero for padding.\n");

    printf("     %%%%    is replaced by `%%'.\n");

    printf("    \n");

    printf("EXAMPLE:\n");

    printf("     rdate                                 --2017-10-23 11:04:51 Monday\n");

    printf("     rdate -f \"%%Y-%%m_%%d\"                   --2017-10-23\n");

    printf("     rdate -f \"%%Y-%%m_%%d\" -c \"day-3\"        --2017-10-20\n");

    printf("     rdate -f \"%%Y-%%m_%%d\" -c \"day+3\"        --2017-10-26\n");

    printf("     rdate -f \"%%Y-%%m_%%d\" -c \"month+3\"      --2017-7-23\n");

    printf("     rdate -f \"%%Y-%%m_%%d\" -c \"year+3\"       --2020-7-23\n");

    printf("    \n");

    printf("    \n");

    printf("    \n");

}



int LeapYear(int year)  //判斷閏年

{

    int ret = 0;

    

    if ((year%4==0 && year%100!=0) || year%400 == 0) {

        ret = 0;

        

        return ret;

    }

    

    else

    {

        ret =1;

        return ret;

    }

}



struct tm * DayAdd(int dayNUm) //dayNum 單位:天 0代表獲取當前時間,整整數代表獲取以後的時間,負數代表向前的時間

{

    

    time_t tt,timetmp;

    struct tm * p = NULL;

    

    time(&tt);

    if (tt == -1) {

        

        perror("time");

        

        return p;

    }

    timetmp = 24*60*60 * dayNUm;

    

    if (dayNUm > 0) {

        tt = tt + timetmp;

    }

    else if (dayNUm < 0){

        tt = tt + timetmp;

    }

    

    p = localtime(&tt);

    

    if (p == NULL) {

        

        return

        p;

    }

    

    return p;

}



struct tm * MonthAdd(int monthNum,struct tm * inTm) //inTm為null表示當前時間

{

    time_t tt;

    struct tm * tmTmp;

    int yearCount = 0;

    

    

    if (inTm == NULL) { //判斷時候獲取當前時間戳

        

        time (&tt);

        tmTmp = localtime(&tt);

    }

    else{

        tmTmp = inTm;

    }

    

    if (monthNum < 0) { //負數代表

        while (1) {

            if (abs(monthNum) >= 12) {

                monthNum+=12;

                yearCount--;

                continue;

            }

            else

            {

                

                break;

            }

        }

        

        if (abs(monthNum) >= (tmTmp->tm_mon+1)) { //判斷傳入的月數是否大於當前的月份,所以tmTmp->tm_mon+1,因為tm_mon從0開始算

            tmTmp->tm_mon = 12 - (abs(monthNum) - (tmTmp->tm_mon));

            yearCount--;

            //            if (monthNum + (tmTmp->tm_mon+1) <= 0) { //判斷是否向前數一年,如果向前一年必須year減一

            //                tmTmp->tm_mon = 12 - (abs(monthNum) - (tmTmp->tm_mon));

            //                yearCount--;

            //            }else

            //            {

            //                tmTmp->tm_mon += monthNum+1;

            //            }

            

            

        }

        else{

            tmTmp->tm_mon+= monthNum;

        }

    }

    else

    {

        

        while (1) { //判斷傳入的引數是否大於12,把大於12的數換算成年,12個月為一年

            if (monthNum >= 12) {

                monthNum -=12;

                yearCount++;

                continue;

            }

            else

            {

                

                break;

            }

        }

        

        if (monthNum + (tmTmp->tm_mon+1) > 12) { //判斷是否需要跨越當前年,如果跨越當前年則年計數器加1

            tmTmp->tm_mon = abs((monthNum + (tmTmp->tm_mon))-12);

            yearCount++;

        }

        else

        {

            tmTmp->tm_mon+= monthNum;

        }

    }

    tmTmp->tm_year+= yearCount;

    

    return tmTmp;

}


struct tm * LastDayOfMonth(int monthNum,struct tm * inTm) //inTm為null表示當前時間

{

    

    int month12[12] = {31,28,31,30,31,30,31,31,30,31,30,31};

    

    time_t tt;

    

    struct tm * tmTmp;

    

    int yearCount = 0;

    

    

    if (inTm == NULL) { //判斷時候獲取當前時間戳

        time(&tt);

        tmTmp = localtime(&tt);

    }

    else

    {

        tmTmp = inTm;

    }

    

    if (monthNum < 0) { //負數代表

        

        

        while (1) {

            if (abs(monthNum) >= 12) {

                monthNum+=12;

                yearCount--;

                

                continue;

            }

            else

            {

                

                break;

            }

        }

        

        if (abs(monthNum) >= (tmTmp->tm_mon+1)) { //判斷傳入的月數是否大於當前的月份,所以tmTmp->tm_mon+1,因為tm_mon從0開始算

            

            tmTmp->tm_mon = 12 - (abs(monthNum) - (tmTmp->tm_mon));

            yearCount--;

            

            //            if (monthNum + (tmTmp->tm_mon+1) <= 0) { //判斷是否向前數一年,如果向前一年必須year減一

            

            

            //                tmTmp->tm_mon = 12 - (abs(monthNum) - (tmTmp->tm_mon));

            

            

            //                yearCount--;

            

            

            //            }else

            

            

            //            {

            

            

            //                tmTmp->tm_mon += monthNum+1;

            

            

            //            }

            

            

        }

        else

        {

            tmTmp->tm_mon += monthNum;

        }

    }

    else

    {

        

        while (1) { //判斷傳入的引數是否大於12,把大於12的數換算成年,12個月為一年

            

            if (monthNum >= 12) {

                monthNum -= 12;

                yearCount++;

                

                continue;

            }

            else

            {

                

                break;

            }

        }

        

        if (monthNum + (tmTmp->tm_mon+1) > 12) { //判斷是否需要跨越當前年,如果跨越當前年則年計數器加1

            

            tmTmp->tm_mon = abs((monthNum + (tmTmp->tm_mon))-12);

            yearCount++;

        }

        else

        {

            tmTmp->tm_mon += monthNum;

        }

    }

    tmTmp->tm_year += yearCount;

    

    

    if(LeapYear(tmTmp->tm_year+1900) == 1) //不是閏年

    {

        tmTmp->tm_mday = month12[tmTmp->tm_mon];

    }

    else

    {

        

        if (tmTmp->tm_mon == 1) {

            tmTmp->tm_mday = month12[tmTmp->tm_mon]+1;

        }

        else

        {

            tmTmp->tm_mday = month12[tmTmp->tm_mon];

        }

    }

    

    

    return tmTmp;

}


struct tm * YearAdd(int yearNum,struct tm * inTm) //inTm為null表示當前時間

{

    return MonthAdd(yearNum*12, inTm);

}


struct tm * WeekAdd(int weekNum) //inTm為null表示當前時間

{

    return DayAdd(weekNum*7);

}



int ToDigit(char * tmp_str)  //獲取需要計算的數字

{

    int ret = 0,num = 0,isMultiSpace = 0,i=0;

    char tmp_array[128];

    for (i=1; i <strlen(tmp_str); i++) {

        if (isdigit(tmp_str[i]) != 0) {

            tmp_array[num]=tmp_str[i];

            num++;

            ret=0;//判斷以獲取到數字,

            continue;

        }else if (tmp_str[i] == ' ')//判斷是否存在空格,允許空格存在,但不允許多個數字引數傳入

        {

            if (ret == 0) { //ret為0表示獲取到數字

                isMultiSpace++;//判斷字串內是否有多個數字

            }

            ret = 1;//如果獲取到空格,則把ret設定成1,表示已經過去過空格

            continue;

        }

        else{//存在除了單個+/-以外的字元

            printf("The value of parameter(-c) include a invalid characcter.");

            exit(4);

        }

    }

    if (isMultiSpace >= 2 && ret==0) { //如果空格超過2並且是剛剛獲取過數字,表示數字超過2個。

        printf("Please enter right format number!!\n");

        printf("If you don't kown what values is avalable,please use -h to get help!\n");

        exit(2);

    }

    ret = atoi(tmp_array);

    return ret;

}


struct tm * Colculation(char * ColStr) //計算函式

{

    int ColNum=0;

    struct tm * tmp_tm = NULL;

    char * tmp_char = calloc(128, sizeof(char));

    if (strcasestr(ColStr, "day") != NULL ){//判斷是否是在日期(天)需要加減

        if (strchr(ColStr, '-') != NULL && strchr(ColStr, '+') != NULL) {//判斷引數內是否同時含有+ -符號

            printf("Please enter right format symbol!!\n");

            printf("If you don't kown what values is avalable,please use -h to get help!\n");

            exit(3);

        }else if (strchr(ColStr, '-') != NULL) {//判斷計算是+或-

            strcpy(tmp_char, strchr(ColStr, '-')); //把-號(含-)後面的內容複製到指定的字串

            ColNum=0-ToDigit(tmp_char);//獲取需要計算的數字

        }else if (strchr(ColStr, '+') != NULL){

            strcpy(tmp_char, strchr(ColStr, '+'));//把+號(含+)後面的內容複製到指定的字串

            ColNum=0+ToDigit(tmp_char);//獲取需要計算的數字

        }

        if (tmp_tm != NULL) {

            free(tmp_tm);

            tmp_tm = NULL;

        }

        tmp_tm = DayAdd(ColNum);//日期(天)計算

    }else if (strcasestr(ColStr, "month") != NULL){//判斷是否是在日期(月)需要加減

        if ((strchr(ColStr, '-') != NULL && strchr(ColStr, '+') != NULL) || strchr(strchr(ColStr, '-')+1,'-') != NULL || strchr(strchr(ColStr, '+')+1,'+') != NULL) {

            printf("Please enter right format symbol!!\n");

            printf("If you don't kown what values is avalable,please use -h to get help!\n");

            exit(3);

        }else if (strchr(ColStr, '-') != NULL) {

            strcpy(tmp_char, strchr(ColStr, '-'));

            ColNum=0-ToDigit(tmp_char);

        }else if (strchr(ColStr, '+') != NULL){

            strcpy(tmp_char, strchr(ColStr, '+'));

            ColNum=0+ToDigit(tmp_char);

        }

        if (tmp_tm != NULL) {

            free(tmp_tm);

            tmp_tm = NULL;

        }

        tmp_tm = MonthAdd(ColNum, NULL);

    }else if (strcasestr(ColStr, "year") != NULL){//判斷是否是在日期(年)需要加減

        if ((strchr(ColStr, '-') != NULL && strchr(ColStr, '+') != NULL) || strchr(strchr(ColStr, '-')+1,'-') != NULL || strchr(strchr(ColStr, '+')+1,'+') != NULL) {

            printf("Please enter right format symbol!!\n");

            printf("If you don't kown what values is avalable,please use -h to get help!\n");

            exit(3);

        }else if (strchr(ColStr, '-') != NULL) {

            strcpy(tmp_char, strchr(ColStr, '-'));

            ColNum=0-ToDigit(tmp_char);

        }else if (strchr(ColStr, '+') != NULL){

            strcpy(tmp_char, strchr(ColStr, '+'));

            ColNum=0+ToDigit(tmp_char);

        }

        if (tmp_tm != NULL) {

            free(tmp_tm);

            tmp_tm = NULL;

        }

        tmp_tm = YearAdd(ColNum, NULL);

    }else{//如果沒有關鍵字(day,month,year)出現,執行這個出口

        printf("Please enter right value of colculation,-c\n");

        printf("If you don't kown what values is avalable,please use -h to get help!\n");

        exit(1);

    }


    if (tmp_char != NULL) {

        free(tmp_char);

        tmp_char = NULL;

    }

    return tmp_tm;

}



int main(int argc, const char * argv[]) {

    time_t tt;

    struct tm * temp_tm = NULL;

    char * str = calloc(1024, sizeof(char));

    int format_num=0,i=0,ret=0;


    time(&tt);

    

    if(argc < 2){//判斷輸入的但是,不帶引數,執行這裡

        temp_tm=localtime(&tt);

        strftime(str, 1024, "%Y-%m-%d %H:%M:%S %A", temp_tm);

        printf("%s\n",str);

    }

    else

    {

        

        for (i=1; i < argc; i++) {//獲取引數

            

            if ( strcasecmp(argv[i], "-h") == 0 ) {

                Func_help();

//                break;

                goto End;

            }else if (strcasecmp(argv[i], "-f") == 0){//-f 表示format,輸出的時間的格式

                i++;

                if (argv[i] == NULL || strcasecmp(argv[i], "-c") == 0) {

                    printf("The value of -f must be specified!!!\n");

                    exit(4);

                }

                format_num = i;//獲取時間格式化的引數的下標位置

                continue;

            }else if (strcasecmp(argv[i], "-c") == 0){//-c 表示colculation,計算的格式,如:day-1

                i++;

                if (argv[i] == NULL  || strcasecmp(argv[i], "-f") == 0) {

                    printf("The value of -c must be specified!!!\n");

                    exit(4);

                }

                temp_tm = Colculation(argv[i]);//執行計算函式,獲取最後需要輸出的struct tm

                continue;

            }else{

                printf("You must enter right parametr.\n");

                printf("If you don't kown what values is avalable,please use -h to get help!\n");

                ret=1;

                goto End;

            }

        }

        if (temp_tm == NULL) {//如果temp_tm為空,則表示使用當前時間

            temp_tm=localtime(&tt);

        }

        if (format_num == 0) {//如果沒有獲取時間格式的下標,則使用預設時間輸出格式

            strftime(str, 1024, "%Y-%m-%d %H:%M:%S %A", temp_tm);

            printf("%s\n",str);

        }else{//使用獲取的時間輸出格式的下標,按照時間格式,給str賦值

            strftime(str, 1024, argv[format_num], temp_tm);

            printf("%s\n",str);

        }

        

        

    }


End:

    if (str != NULL) {

        free(str);

        str=NULL;

    }

    if(temp_tm != NULL){

        free(temp_tm);

        temp_tm = NULL;

    }

    return ret;

}



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28572479/viewspace-2146213/,如需轉載,請註明出處,否則將追究法律責任。

相關文章