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'));
}