Convert textual date and time to ATL::CTime

by Michael Haephrati   Last Updated January 14, 2018 12:26 PM

Given a textual date and time, for example:

Sat, 13 Jan 2018 07:54:39 -0500 (EST)

How can I convert it into ATL / MFC CTime?

The function should return (in case of my example):

CTime(2018,1,13,7,54,39)

Update:

I tried writing the following function but it seems that ParseDateTime() always fail.

CTime DateTimeString2CTime(CString DateTimeStr)
{
    COleDateTime t;
    if (t.ParseDateTime(DateTimeStr))
    {
        CTime result(t);
        return result;
    }
    return (CTime)NULL;
}


Answers 2


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>

int main()
{
    std::wstring const s = L"Sat, 13 Jan 2018 07:54:39 -0500 (EST)";
    std::wregex const r{ LR"(.*(\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d).*)" };
    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';

        // TODO: convert sub matches into numbers for CTime constructor, e. g.
        int day = std::stoi( m[ 1 ] );
    }
}

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::wstrings aswell.

If necessary, catch exceptions that can be thrown by regex library aswell as std::stoi. I've omitted this code for brevity.


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.

zett42
zett42
January 13, 2018 23:45 PM

As an alternative to manual parsing, you could use the COleDateTime Class, and it's member COleDateTime::ParseDateTime:

bool ParseDateTime(  
 LPCTSTR lpszDate,
 DWORD dwFlags = 0,
 LCID lcid = LANG_USER_DEFAULT) throw();

From the docs:

The lpszDate parameter can take a variety of formats.
For example, the following strings contain acceptable date/time formats:

"25 January 1996"
"8:30:00"
"20:30:00"
"January 25, 1996 8:30:00"
"8:30:00 Jan. 25, 1996"
"1/25/1996 8:30:00" // always specify the full year,
// even in a 'short date' format

From there you could convert to CTime if needed.

Danny_ds
Danny_ds
January 14, 2018 00:34 AM

Related Questions


Why is this script changing my file's ctime?

Updated June 16, 2017 23:26 PM

Human readable string of 64bits time_t value

Updated May 03, 2015 21:11 PM

C++ Current System Time - "The right way"

Updated July 01, 2017 01:26 AM

Loading a bitmap to a window

Updated April 06, 2015 20:11 PM