user4656543
user4656543

Reputation:

strtotime function in C

I'm trying to make a universal function in C that can convert a date from any server log file in any format into a timestamp since I want to log how frequent potential hackers failed to crack the server. In PHP I can use strtotime but I don't think such functionality exists in C.

If all log files used the same time format in the form of YYYY-MM-DD HH:MM:SS then I could get away with code like this:

//tmadd = 19 bytes as a char reserved for date/time plus trailing null
long result=0;
struct tm x;
if (sscanf(tmadd,"%i-%i-%i %i:%i:%i",&x.tm_year,&x.tm_mon,&x.tm_mday,&x.tm_hour,&x.tm_min,&x.tm_sec) >= 6){x.tm_year-=1900;result=mktime(&x);}

The problem is some logs have months as words and I have yet to find a function to capture the numeric equivalent.

I want to be able to do the whole conversion within one function.

Is there an easy function I can use to get a raw timestamp from any specified date in any common format? I'm basically looking for a way to roll off my own PHP's strtotime().

Upvotes: 1

Views: 2558

Answers (1)

M Oehm
M Oehm

Reputation: 29126

A function to convert any time format is a very ambitious project as a A look at the recognised date formats for the PHP strtotime function shows.

But if you have a few known timestamp formats in use on your servers, you can check them separately:

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

int strtomonth(int *mm, const char *str)
{
    static const char *sname[] = {
        "jan", "feb", "mar", "apr", "may", "jun",
        "jul", "aug", "sep", "oct", "nov", "dec",
        NULL
    };    
    int i;

    for (i = 0; sname[i]; i++) {
        if (strcmp(sname[i], str) == 0) {
            *mm = i + 1;
            return 1;
        }
    }

    return 0;
}

int strtotime(time_t *time, const char *s)
{
    struct tm tm;
    int dd, mm, yy;
    int hrs, min, sec;
    char buf[20];

    if (sscanf(s, "%u-%u-%u %u:%u:%u",
        &yy, &mm, &dd, &hrs, &min, &sec) == 6) goto okay;

    if (sscanf(s, "%u-%19[a-zA-Z]-%u %u:%u:%u",
        &yy, buf, &dd, &hrs, &min, &sec) == 6
        && strtomonth(&mm, buf)) goto okay;

    return 0;

  okay:
    // Do some sanity checking to rule out 2015-mar-35 and such

    tm.tm_sec = sec;
    tm.tm_min = min;
    tm.tm_hour = hrs;
    tm.tm_mday = dd;
    tm.tm_mon = mm - 1;
    tm.tm_year = yy - 1900;

    *time = mktime(&tm);
    return 1;
}

This rather long but still very rough code, which doesn't check whether the dates and times are reasonable, recognises the two formats "2015-05-30 18:13:04"and "2015-may-30 18:13:04". You can add more as you encounter them.

The goto may be ugly, but I think it is a good way to get to the common code at the end. The month lookup is very crude, but should be okay for short strings.

Upvotes: 3

Related Questions