"undefined reference to strptime"之自己定義strptime函式

weixin_33982670發表於2018-03-18

簡單介紹

  strptime()函式可以依照特定時間格式將字串轉換為時間型別。簡單點說可以將字串時間轉化為時間戳。

這個函式包括在time.h標頭檔案裡,在Unix或者類Unix系統中,我們會常常接觸到。可是到了跑Nuttx系統的Pixhawk。真是醉了,非常多東西都沒有,或者少了非常多東西,比方time.h中就沒有這個函式的實現,又如dirent.h中的一些檔案型別的巨集定義也沒有了。

可是我們非常須要,比方在時間的比較上,我們不能去拿字串去操作來比較。會搞死人的。直接得到時間戳,三下兩除二就搞定了。那就要用到strptime這個函式了。

實現

mystrptime.c
/*
 * Note:因time.h中沒有strptime函式(UNIX中是有的),本檔案是對strptime功能的自己定義實現;
 * We do not implement alternate representations. However, we always
 * check whether a given modifier is allowed for a certain conversion.
 */
#include "mystrptime.h"


static const char *day[7] = {
    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
    "Friday", "Saturday"
};
static const char *abday[7] = {
    "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
};
static const char *mon[12] = {
    "January", "February", "March", "April", "May", "June", "July",
    "August", "September", "October", "November", "December"
};
static const char *abmon[12] = {
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static const char *am_pm[2] = {
    "AM", "PM"
};


static int conv_num(const char **buf, int *dest, int llim, int ulim)
{
    int result = 0;

    /* The limit also determines the number of valid digits. */
    int rulim = ulim;

    if (**buf < '0' || **buf > '9')
        return (0);

    do {
        result *= 10;
        result += *(*buf)++ - '0';
        rulim /= 10;
    } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');

    if (result < llim || result > ulim)
        return (0);

    *dest = result;
    return (1);
}

char * mystrptime(const char *buf, const char *fmt, struct tm *tm)
{
    char c;
    const char *bp;
    size_t len = 0;
    int alt_format, i, split_year = 0;

    bp = buf;

    while ((c = *fmt) != '\0') {
        /* Clear `alternate' modifier prior to new conversion. */
        alt_format = 0;

        /* Eat up white-space. */
        if (isspace(c)) {
            while (isspace(*bp))
                bp++;

            fmt++;
            continue;
        }

        if ((c = *fmt++) != '%')
            goto literal;


again:      switch (c = *fmt++) {
        case '%':   /* "%%" is converted to "%". */
literal:
            if (c != *bp++)
                return (0);
            break;

        /*
         * "Alternative" modifiers. Just set the appropriate flag
         * and start over again.
         */
        case 'E':   /* "%E?" alternative conversion modifier. */
            LEGAL_ALT(0);
            alt_format |= ALT_E;
            goto again;

        case 'O':   /* "%O?" alternative conversion modifier. */
            LEGAL_ALT(0);
            alt_format |= ALT_O;
            goto again;

        /*
         * "Complex" conversion rules, implemented through recursion.
         */
        case 'c':   /* Date and time, using the locale's format. */
            LEGAL_ALT(ALT_E);
            if (!(bp = mystrptime(bp, "%x %X", tm)))
                return (0);
            break;

        case 'D':   /* The date as "%m/%d/%y". */
            LEGAL_ALT(0);
            if (!(bp = mystrptime(bp, "%m/%d/%y", tm)))
                return (0);
            break;

        case 'R':   /* The time as "%H:%M". */
            LEGAL_ALT(0);
            if (!(bp = mystrptime(bp, "%H:%M", tm)))
                return (0);
            break;

        case 'r':   /* The time in 12-hour clock representation. */
            LEGAL_ALT(0);
            if (!(bp = mystrptime(bp, "%I:%M:%S %p", tm)))
                return (0);
            break;

        case 'T':   /* The time as "%H:%M:%S". */
            LEGAL_ALT(0);
            if (!(bp = mystrptime(bp, "%H:%M:%S", tm)))
                return (0);
            break;

        case 'X':   /* The time, using the locale's format. */
            LEGAL_ALT(ALT_E);
            if (!(bp = mystrptime(bp, "%H:%M:%S", tm)))
                return (0);
            break;

        case 'x':   /* The date, using the locale's format. */
            LEGAL_ALT(ALT_E);
            if (!(bp = mystrptime(bp, "%m/%d/%y", tm)))
                return (0);
            break;

        /*
         * "Elementary" conversion rules.
         */
        case 'A':   /* The day of week, using the locale's form. */
        case 'a':
            LEGAL_ALT(0);
            for (i = 0; i < 7; i++) {
                /* Full name. */
                len = strlen(day[i]);
                if (strncasecmp(day[i], bp, len) == 0)
                    break;

                /* Abbreviated name. */
                len = strlen(abday[i]);
                if (strncasecmp(abday[i], bp, len) == 0)
                    break;
            }

            /* Nothing matched. */
            if (i == 7)
                return (0);

            tm->tm_wday = i;
            bp += len;
            break;

        case 'B':   /* The month, using the locale's form. */
        case 'b':
        case 'h':
            LEGAL_ALT(0);
            for (i = 0; i < 12; i++) {
                /* Full name. */
                len = strlen(mon[i]);
                if (strncasecmp(mon[i], bp, len) == 0)
                    break;

                /* Abbreviated name. */
                len = strlen(abmon[i]);
                if (strncasecmp(abmon[i], bp, len) == 0)
                    break;
            }

            /* Nothing matched. */
            if (i == 12)
                return (0);

            tm->tm_mon = i;
            bp += len;
            break;

        case 'C':   /* The century number. */
            LEGAL_ALT(ALT_E);
            if (!(conv_num(&bp, &i, 0, 99)))
                return (0);

            if (split_year) {
                tm->tm_year = (tm->tm_year % 100) + (i * 100);
            } else {
                tm->tm_year = i * 100;
                split_year = 1;
            }
            break;

        case 'd':   /* The day of month. */
        case 'e':
            LEGAL_ALT(ALT_O);
            if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
                return (0);
            break;

        case 'k':   /* The hour (24-hour clock representation). */
            LEGAL_ALT(0);
            /* FALLTHROUGH */
        case 'H':
            LEGAL_ALT(ALT_O);
            if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
                return (0);
            break;

        case 'l':   /* The hour (12-hour clock representation). */
            LEGAL_ALT(0);
            /* FALLTHROUGH */
        case 'I':
            LEGAL_ALT(ALT_O);
            if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
                return (0);
            if (tm->tm_hour == 12)
                tm->tm_hour = 0;
            break;

        case 'j':   /* The day of year. */
            LEGAL_ALT(0);
            if (!(conv_num(&bp, &i, 1, 366)))
                return (0);
            tm->tm_yday = i - 1;
            break;

        case 'M':   /* The minute. */
            LEGAL_ALT(ALT_O);
            if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
                return (0);
            break;

        case 'm':   /* The month. */
            LEGAL_ALT(ALT_O);
            if (!(conv_num(&bp, &i, 1, 12)))
                return (0);
            tm->tm_mon = i - 1;
            break;

        case 'p':   /* The locale's equivalent of AM/PM. */
            LEGAL_ALT(0);
            /* AM? */
            if (strcasecmp(am_pm[0], bp) == 0) {
                if (tm->tm_hour > 11)
                    return (0);

                bp += strlen(am_pm[0]);
                break;
            }
            /* PM? */
            else if (strcasecmp(am_pm[1], bp) == 0) {
                if (tm->tm_hour > 11)
                    return (0);

                tm->tm_hour += 12;
                bp += strlen(am_pm[1]);
                break;
            }

            /* Nothing matched. */
            return (0);

        case 'S':   /* The seconds. */
            LEGAL_ALT(ALT_O);
            if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
                return (0);
            break;

        case 'U':   /* The week of year, beginning on sunday. */
        case 'W':   /* The week of year, beginning on monday. */
            LEGAL_ALT(ALT_O);
            /*
             * XXX This is bogus, as we can not assume any valid
             * information present in the tm structure at this
             * point to calculate a real value, so just check the
             * range for now.
             */
             if (!(conv_num(&bp, &i, 0, 53)))
                return (0);
             break;

        case 'w':   /* The day of week, beginning on sunday. */
            LEGAL_ALT(ALT_O);
            if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
                return (0);
            break;

        case 'Y':   /* The year. */
            LEGAL_ALT(ALT_E);
            if (!(conv_num(&bp, &i, 0, 9999)))
                return (0);

            tm->tm_year = i - TM_YEAR_BASE;
            break;

        case 'y':   /* The year within 100 years of the epoch. */
            LEGAL_ALT(ALT_E | ALT_O);
            if (!(conv_num(&bp, &i, 0, 99)))
                return (0);

            if (split_year) {
                tm->tm_year = ((tm->tm_year / 100) * 100) + i;
                break;
            }
            split_year = 1;
            if (i <= 68)
                tm->tm_year = i + 2000 - TM_YEAR_BASE;
            else
                tm->tm_year = i + 1900 - TM_YEAR_BASE;
            break;

        /*
         * Miscellaneous conversions.
         */
        case 'n':   /* Any kind of white-space. */
        case 't':
            LEGAL_ALT(0);
            while (isspace(*bp))
                bp++;
            break;


        default:    /* Unknown/unsupported conversion. */
            return (0);
        }


    }

    /* LINTED functional specification */
    return ((char *)bp);
}


time_t to_seconds(const char *date,int mode)
{
    struct tm storage={0,0,0,0,0,0,0,0,0};
    char *p=NULL;
    time_t retval=0;

    if(1 == mode)p=(char *)mystrptime(date,"%Y-%m-%d",&storage);
    else if(0 == mode)p=(char *)mystrptime(date,"%Y_%m_%d",&storage);
    if(p==NULL)
    {
        retval=0;
    }
    else
    {
        retval=mktime(&storage);
    }
    return retval;
}
mystrptime.h
#ifndef MYSTRPTIME_H_
#define MYSTRPTIME_H_

#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <string.h>

#define ALT_E           0x01
#define ALT_O           0x02
#define LEGAL_ALT(x)        { if (alt_format & ~(x)) return (0); }
#define TM_YEAR_BASE 1900

char *mystrptime(const char *buf, const char *fmt, struct tm *tm);
time_t to_seconds(const char *date,int mode);

#endif

測試

/*Test*/
/*
#intclude <stdio.h>
#include "mystrptime.h"

int main ()
{
    time_t ts;
    ts = to_seconds("2015-07-29",1);
    //ts = to_seconds("2015_07_29",0);
    printf("ts=%d\n",ts);
    return(0);
}
*/

相關文章