0

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?

Moige
  • 169
  • 8
  • "31122021"- that's January 31st, 22021? That's a good 200 centuries out. You may want a less ambiguous date format. – MSalters Nov 05 '21 at 10:51
  • @MSalters That's a standard format though. `%Y` is supposed to parse the year as a 4-digit number (with leading zeroes permitted but not required). Also, this exact example is handled correctly when compiling with CLang. – Moige Nov 05 '21 at 11:04
  • 1
    Fixed in 16.9 (VS2019): https://github.com/microsoft/STL/issues/944 – MSalters Nov 05 '21 at 11:10

1 Answers1

1

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'));
}
Moige
  • 169
  • 8