c++11 Datum speichern und auslesen



  • Ich habe viel gegooglet und leider nichts brauchbares für mein Problem gefunden, vielleicht sitzt das Problem auch vor dem Rechner.

    Was ich will:

    <creat_date> 13:50 - 1 JUN 2014 </create_date>
    

    Ich möchte mit C++ das Datum in einen Format meiner Wahl speichern und auslesen. Im Internet bin ich auf std::put_time gestoßen, leider ist diese Funktion in GCC noch nicht definiert. Die andere Sache ist, das Datum dann auch wieder ins Programm einzulesen. Im Internet finde ich nur Beispiele die ctime abspeichern, aber ich will dass das Datum auch in der XML File lesbar ist.

    Gibt es dafür eine einfache Bibliothek, oder geht das auch mit Chrono?



  • schreib das Datum doch als fest formatierten String raus, den du beim Einlesen parst.



  • Mit std::get_time und std::put_time sollte es so gehen:

    #include <iostream>
    #include <ctime> // std::tm
    #include <sstream>
    
    int main()
    {
        using namespace std;
        tm zeit;
        istringstream in( "13:50 - 1 Jun 2014" );
        const char* Format = "%H:%M - %d %b %Y";
        if( in >> get_time( &zeit, Format ) )
        {
            cout << "Gelesen: " << put_time( &zeit, Format ) << endl;
        }
        return 0;
    }
    

    Ausgabe:

    Gelesen: 13:50 - 01 Jun 2014
    

    wobei get- und put-_time nur Wrapper (genauer Manipulatoren) für die Facetten std::time_get und std::time_put sind. Und die gab es bereits vor C++11.
    Schau Dir in diesem Beitrag zur Zeitausgabe mal den Manipulator ' now ' an.

    Gruß
    Werner



  • Werner Salomon schrieb:

    Mit std::get_time und std::put_time sollte es so gehen:

    #include <iostream>
    #include <ctime> // std::tm
    #include <sstream>
    
    #include <iomanip> //hier sollten die funktionen deklariert sein :/
    
    int main()
    {
        using namespace std;
        tm zeit;
        istringstream in( "13:50 - 1 Jun 2014" );
        const char* Format = "%H:%M - %d %b %Y";
        if( in >> get_time( &zeit, Format ) )
        {
            cout << "Gelesen: " << put_time( &zeit, Format ) << endl;
        }
        return 0;
    }
    

    Ausgabe:

    Gelesen: 13:50 - 01 Jun 2014
    

    wobei get- und put-_time nur Wrapper (genauer Manipulatoren) für die Facetten std::time_get und std::time_put sind. Und die gab es bereits vor C++11.
    Schau Dir in diesem Beitrag zur Zeitausgabe mal den Manipulator ' now ' an.

    Gruß
    Werner

    ||=== Build: Debug in random (compiler: GNU GCC Compiler) ===|
    ||In function ‘int main()’:|
    error: ‘get_time’ was not declared in this scope|
    error: ‘put_time’ was not declared in this scope|
    ||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
    
    g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2
    


  • #include <iostream>
    #include <sstream>
    #include <string>
    #include <locale>
    #include <ctime>
    #include <iomanip>
    
    int main()
    {
        std::wstring input = L"2011-Februar-18 23:12:34";
        std::tm t;
        std::wistringstream ss(input);
        ss.imbue(std::locale("de_DE"));
        ss >> std::get_time(&t, L"%Y-%b-%d %H:%M:%S"); //error: ‘get_time’ is not a member of ‘std’|
        std::cout << std::asctime(&t);
    }
    

    Hier das gleiche Problem: http://en.cppreference.com/w/cpp/locale/time_get 😮



  • kks schrieb:

    Hier das gleiche Problem: http://en.cppreference.com/w/cpp/locale/time_get 😮

    Werner Salomon schrieb:

    wobei get- und put-_time nur Wrapper (genauer Manipulatoren) für die Facetten std::time_get und std::time_put sind. Und die gab es bereits vor C++11.
    Schau Dir in diesem Beitrag zur Zeitausgabe mal den Manipulator ' now ' an.

    .. dann schreibe Dir die Dinger doch selber. Sind doch nur kleine Wrapper - wie das geht - siehe Link. Falls unklar, liefere ich sie Dir heute Abend.



  • Ich habe jetzt die C Funktionen gewrappt, diese würden für meine Ansprüche auch reichen, aber leider ist strptime nur für Unix 😞

    #include <iostream>
    #include <ctime>
    #include <chrono>
    #include <string>
    #include <stdexcept>
    
    std::string putTime( const std::time_t& time, const std::string& format )
    {
        char mbstr[100];
        if ( std::strftime( mbstr, sizeof(mbstr), format.c_str(), std::localtime( &time ) ) )
        {
            return mbstr;
        }
        else
        {
            throw std::invalid_argument("wrong format");
        }
    }
    
    std::time_t getTime( const std::string& time ,const std::string& pattern )
    {
        struct tm tm;
        if( strptime( time.c_str() , pattern.c_str(), &tm ) != NULL )
        {
            return mktime( &tm );
        }
        else
        {
            throw std::invalid_argument("wrong format");
        }
    }
    
    int main()
    {
        auto timePoint = std::chrono::system_clock::now();
        auto timeT     = std::chrono::system_clock::to_time_t( timePoint );
    
        auto s = putTime( timeT, "%Y-%b-%d %H:%M:%S" );
        auto foo = getTime( s, "%Y-%b-%d %H:%M:%S" );
        std::cout << ctime(&foo);
    }
    

    Gibt es hier eine plattformunabhängige Lösung? Habe leider bis jetzt keine gefunden.



  • kks schrieb:

    Gibt es hier eine plattformunabhängige Lösung? Habe leider bis jetzt keine gefunden.

    Ja natürlich - die Facetten std::time_get und std::time_put. Und die waren schon unter C++98 standardisiert. Sie sind im Header <locale> definiert und Ich kann mir nicht vorstellen, dass die in der Library von GNU 4.8. nicht enthalten sind.

    Kläre doch bitte zunächst, ob die beiden Facetten in Deinem Header <locale> enthalten sind. Das sollte übersetzen:

    #include <iostream> // cout
    #include <locale>   // std::time_get
    int main()
    {
        const std::time_get< char >& pups = std::use_facet< std::time_get< char > >( std::cout.getloc() );
    }
    

    Einen Manipulator mit der Syntax von std::get_time und std::put_time zu basteln ist dann kein großes Problem. Ich lege my_std::get_time mal vor:

    #include <iostream> // cout
    #include <locale>   // std::time_get
    #include <ctime>    // std::tm
    #include <sstream>  // nur für die Demo, s.main
    
    namespace my_std     // 'my_std' dann gibt's keine Namenskollision
    {
        namespace detail // das ist jetzt ein Implementierungsdetail
        {
            template< typename E >
            struct TimeObject
            {
                TimeObject( std::tm* t, const E* format )
                    : tm_( t )
                    , fmtFirst_( format )
                    , fmtLast_( format )
                {
                    for( ; *fmtLast_ != 0; ++fmtLast_ )
                        ;
                }
                std::tm* tm_;
                const E* fmtFirst_;
                const E* fmtLast_;
            };
    
            template< typename E, typename Traits >     // Extractor für TimeObject<>
            std::basic_istream< E, Traits >& operator>>( std::basic_istream< E, Traits >& in, TimeObject< E > t )
            {
                std::basic_istream< E, Traits >::sentry ok( in );
                if( ok )
                {
                    std::ios_base::iostate state = std::ios_base::goodbit;
                    try
                    {
                        typedef std::time_get< E > TimeGetFac;
                        typedef TimeGetFac::iter_type Iter;
                        const TimeGetFac& tmGetFac = std::use_facet< TimeGetFac >( in.getloc() );
                        tmGetFac.get( Iter(in), Iter(), in, state, t.tm_, t.fmtFirst_, t.fmtLast_ );
                    }
                    catch( ... )
                    {
                        state |= std::ios_base::badbit;
                        if( in.exceptions() & std::ios_base::badbit )
                            throw;
                    }
                    in.setstate( state );
                }
                return in;
            }
        } // detail
    
        // -- der eigentliche Manipulator besteht aus einer Factoryfunction, die ein TimeObject erzeugt
        template< typename E >
        detail::TimeObject< E > get_time( std::tm* t, const E* format )
        {
            return detail::TimeObject< E >( t, format );
        }
    }
    
    int main()
    {
        using namespace std;
        tm zeit;
        istringstream in("13:50 - 1 Jun 2014");
        const char* format = "%H:%M - %d %b %Y";
        if( in >> my_std::get_time( &zeit, format ) )
        {
            cout << "Gelesen: " << zeit.tm_hour << ":" << zeit.tm_min << " am " << zeit.tm_mday << "." << (zeit.tm_mon+1) << " im Jahre " << (zeit.tm_year+1900) << endl;
        }
        return 0;
    }
    

    Gruß
    Werner


  • Mod

    Werner Salomon schrieb:

    kks schrieb:

    Gibt es hier eine plattformunabhängige Lösung? Habe leider bis jetzt keine gefunden.

    Ja natürlich - die Facetten std::time_get und std::time_put. Und die waren schon unter C++98 standardisiert. Sie sind im Header <locale> definiert und Ich kann mir nicht vorstellen, dass die in der Library von GNU 4.8. nicht enthalten sind.

    Das ist tatsächlich der Fall. Diese Features sind nur in den allerneuesten Entwicklungszweigen.



  • Vielen Dank für die Antworten. std::time_get funktioniert bei mir auch, aber das habe ich zu spät getesten. Habe mir in der Zeit schnell selbt was geschrieben, basierend auf die erste Antwort:

    daddy_felix schrieb:

    schreib das Datum doch als fest formatierten String raus, den du beim Einlesen parst.

    #include <sstream>
    #include <ctime>
    #include <stdexcept>
    #include <string>
    #include <chrono>
    #include <iostream>
    #include <locale>
    
    std::string timeToString( const tm* const time )
    {
        std::string date;
    
        if( time->tm_hour < 10 )
        {
            date += "0";
        }
        date += std::to_string( time->tm_hour ) + ":";
    
        if( time->tm_min < 10 )
        {
            date += "0";
        }
        date += std::to_string( time->tm_min ) + ":";
    
        if( time->tm_sec < 10 )
        {
            date += "0";
        }
        date += std::to_string( time->tm_sec ) + " - ";
    
        date += std::to_string( time->tm_year + 1900 ) + "/"
             +  std::to_string( time->tm_mon + 1 ) + "/"
             +  std::to_string( time->tm_mday );
    
        return date;
    }
    
    std::time_t stringToTime( const std::string& str )
    {
        //read values from string
        std::stringstream ss( str );
        int hour;
        if( !( ss >> hour ) )
        {
            throw std::invalid_argument("wrong format: hour");
        }
    
        char trash;
        ss >> trash;
    
        int minutes;
        if( !( ss >> minutes ) )
        {
            throw std::invalid_argument("wrong format: minutes");
        }
    
        ss >> trash;
    
        int seconds;
        if( !( ss >> seconds ) )
        {
            throw std::invalid_argument("wrong format: seconds");
        }
    
        ss >> trash;
    
        int year;
        if( !( ss >> year ) )
        {
            throw std::invalid_argument("wrong format: year");
        }
    
        ss >> trash;
    
        int month;
        if( !( ss >> month ) )
        {
            throw std::invalid_argument("wrong format: month");
        }
    
        ss >> trash;
    
        int day;
        if( !( ss >> day ) )
        {
            throw std::invalid_argument("wrong format: day");
        }
    
        //format for tm
        hour += 1;
        month -= 1;
        year  -= 1900;
    
        struct tm time;
    
        time.tm_hour = hour;
        time.tm_min  = minutes;
        time.tm_sec  = seconds;
        time.tm_year = year;
        time.tm_mon  = month;
        time.tm_mday = day;
    
        return mktime( &time );
    }
    
    int main()
    {
        std::locale("");
        auto now = std::chrono::system_clock::now();
        auto t   = std::chrono::system_clock::to_time_t( now );
    
        auto s = timeToString( std::localtime( &t ) );
        std::cout << s << "\n";
        auto time = stringToTime(s);
        std::cout << time << "\n";
        std::cout << timeToString( std::localtime( &time ) );
    }
    

    Ich bin noch relativ neu in C++ und mit Streams habe ich mich noch nicht viel befasst, wird sich jetzt ändern :D. Aber trozdem danke für den Code Werner.


Anmelden zum Antworten