You have to parse the string into the individual time components, convert these to integers and pass them to the appropriate CTime
constructor.
There are many ways for parsing, one of the most straightforward and easy-to-maintain ways is to use regular expressions (once you get used to the syntax):
#include <iostream>
#include <regex>
void test( std::wstring const& s, std::wregex const& r );
int main()
{
std::wregex const r{
LR"(.*?)" // any characters (none or more)
LR"((\d+))" // match[1] = day
LR"(\s*)" // whitespace (none or more)
LR"((Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))" // match[2] = month
LR"(\s*)" // whitespace (none or more)
LR"((\d+))" // match[3] = year
LR"(\s+)" // whitespace (1 or more)
LR"((\d+))" // match[4] = hour
LR"(\s*:\s*)" // whitespace (none ore more), colon (1), whitespace (none ore more)
LR"((\d+))" // match[5] = minute
LR"((?:\s*:\s*(\d+))?)" // match[6] = second (none or more)
LR"(.*)" // any characters (none or more)
, std::regex_constants::icase };
test( L"Sat, 13 Jan 2018 07:54:39 -0500 (EST)", r );
test( L"Wed, 10 jan2018 18:30 +0100", r );
test( L"10Jan 2018 18 :30 : 00 + 0100", r );
}
void test( std::wstring const& s, std::wregex const& r )
{
std::wsmatch m;
if( regex_match( s, m, r ) )
{
std::wcout
<< L"Day : " << m[ 1 ] << L'\n'
<< L"Month : " << m[ 2 ] << L'\n'
<< L"Year : " << m[ 3 ] << L'\n'
<< L"Hour : " << m[ 4 ] << L'\n'
<< L"Minute : " << m[ 5 ] << L'\n'
<< L"Second : " << m[ 6 ] << L'\n';
}
else
{
std::wcout << "no match" << '\n';
}
std::wcout << std::endl;
}
Live demo.
You specify a pattern (the r
variable) that encloses each component in parenthesis. After the call to regex_match
, the result is stored in the variable m
where you can access each component (aka sub match) through the subscript operator. These are std::wstring
s aswell.
If necessary, catch exceptions that can be thrown by regex library aswell as std::stoi
. I've omitted this code for brevity.
Edit:
After OP commented that a more robust parsing is required, I modified the regex accordingly.
As can be seen in the calls to the test()
function, the whitespace requirements are more relaxed now. Also the seconds part of the timestamp is now optional. This is implemented using a non-capturing group that is introduced with (?:
and ends with )
. By putting a ?
after that group, the whole group (including whitespace, :
and digits) can occur none or one time, but only the digits are captured.
Note: LR"()"
designates a raw string literal to make the regex more readable (it avoids escaping the backslash). So the outer parenthesis are not part of the actual regex!
For manual parsing one could employ std::wstringstream
. In my opinion, the only advantage over regular expressions is propably better performance. Otherwise this solution is just harder to maintain, for instance if the time format must be changed in the future.
#include <iostream>
#include <sstream>
#include <array>
#include <string>
int month_to_int( std::wstring const& m )
{
std::array<wchar_t const*, 12> names{ L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec" };
for( std::size_t i = 0; i < names.size(); ++i )
{
if( names[ i ] == m )
return i + 1;
}
return 0;
}
int main()
{
std::wstringstream s{ L"Sat, 13 Jan 2018 07:54:39 -0500 (EST)" };
std::wstring temp;
int day, month, year, hour, minute, second;
// operator >> reads until whitespace delimiter
s >> temp;
s >> day;
s >> temp; month = month_to_int( temp );
s >> year;
// use getline to explicitly specify the delimiter
std::getline( s, temp, L':' ); hour = std::stoi( temp );
std::getline( s, temp, L':' ); minute = std::stoi( temp );
// last token separated by whitespace again
s >> second;
std::cout
<< "Day : " << day << '\n'
<< "Month : " << month << '\n'
<< "Year : " << year << '\n'
<< "Hour : " << hour << '\n'
<< "Minute : " << minute << '\n'
<< "Second : " << second << '\n';
}
Live demo.
Again, no error handling here for brevity. You should check stream state after each input operation or call std::wstringstream::exceptions()
after construction to enable exceptions and handle them.