Home > Net >  How to parse 8-digit date in C ?
How to parse 8-digit date in C ?

Time:11-08

I use std::get_time to parse dates from text. In most cases it is sufficient, but when reading dates with no separators (e.g. 31122021, with format "%d%m%Y") I always get a failure. I use this because I saw it described as an equivalent to python's strptime (https://stackoverflow.com/a/33542189/15061775) which does manage this use case (How to parse an 8 digit number as a date?).

Here is my code (tested MRE) :

#include <cassert>
#include <ctime>
#include <iomanip>
#include <sstream>

#define MAKEDATE(d,m,y) (((y&0xFFFF)<<16)|((m&0xFF)<<8)|(d&0xFF))
uint32_t Get_Date(const char *str_date, const char **out, const char *format)
{
    std::tm dt = {};
    std::istringstream stream(str_date);
    stream >> std::get_time(&dt, format);
    if (stream.fail())
    {
        if (out) *out = NULL;
        return MAKEDATE(1, 1, 1900);
    }
    else
    {
        if (out) *out = str_date   (int)stream.tellg();
        return MAKEDATE(dt.tm_mday, 1   dt.tm_mon, 1900   dt.tm_year);
    }
}

int main(void)
{
    assert(Get_Date("31122021", NULL, "%d%m%Y") == MAKEDATE(31, 12, 2021));
}

I compile it using VS2017's default compiler settings using MFC and CLI, with MSVC 19.10.25027.

Did I make a mistake? Is there another flag or set of flags I could use? Is there another, simple parsing method?

CodePudding user response:

This is a compiler specific issue. If this specific method needs to handle this specific input, then you have to use a different compiler.

Quoting this link ;

It appears that std::get_time in MSVC 14.0 does not parse undelimited date and time values, such as those found in the ISO-8601 basic format. The following code fails with MSVC, but works properly with GCC 5.2. <code example>

and

Seems that it is known: <defunct, very old link>

one can conclude MSVC-compiled std::get_time has never been able to parse non-separated input. GCC reportedly works, and CLang definitely does, so MSVC is the odd one out.

If switching compilers is not worth the hassle, a more specific parsing method will do.

// Assuming str_date is guaranteed to be 8 digits
uint32_t Get_Date_YMD(const char *str_date)
{
    return
        (((str_date[0] - '0') * 1000  
        (  str_date[1] - '0') * 100  
        (  str_date[2] - '0') * 10  
        (  str_date[3] - '0')) << 16) |
        (((str_date[4] - '0') * 10  
        (  str_date[5] - '0')) << 8) |
        (( str_date[6] - '0') * 10  
        (  str_date[7] - '0'));
}
  • Related