Probleme mit std::get_time



  • Hallo,

    Habe Probleme mit std::get_time. Versuchte den Fehler auf Ideone zu reproduzieren. Komisch, dort klappt es.

    #include <iostream>
    #include <sstream>
    #include <ctime>
    //#include <codecvt>
    #include <iomanip>
    #include <locale>
    #include <boost/date_time.hpp>
    //using namespace std;
    
    std::string DateToString(const boost::gregorian::date& date)
    {
    	std::tm tm = to_tm(date);
    
    	std::ostringstream stream;
    	//stream.imbue(std::locale("en_us.utf-8"));
    	stream.imbue(std::locale(""));
    
    	stream << std::put_time(&tm, "%x");
    	
    	std::cout << stream.str() << '\n';
    	
    	return stream.str();
    }
    
    
    boost::gregorian::date StringToDate(const std::string& string)
    {
    	std::istringstream stream(string);
    	//stream.imbue(std::locale("en_us.utf-8"));
    	stream.imbue(std::locale(""));
    	
    	std::tm tm = {};
    	stream >> std::get_time(&tm, "%x");
    
    	boost::gregorian::date ret;
    
    	if (!stream.fail()) 
    	{
    		ret = boost::gregorian::date_from_tm(tm);
    	}
    	else 
    	{
    		ret = boost::gregorian::date(boost::gregorian::not_a_date_time);
    	}
    
    	return ret;
    }
    
    int main() 
    {
    	boost::gregorian::date today(2020, 2, 9);
    	
    	std::string todayString = DateToString(today);
    	auto todayFromString = StringToDate(todayString);
    	DateToString(todayFromString);
    	
    	auto yesterdayFromString = StringToDate("01/09/2020");
    	DateToString(yesterdayFromString);
    	
    	return 0;
    }
    

    Mache jetzt Denkpause 😴 , für Tipps bin ich dankbar. Danke im voraus.

    Edit: Also das Problem besteht mit msvc immer noch. Anhand eines (identischen) locale
    stream.imbue(std::locale(""))
    und format strings ("%x")
    stream << std::put_time(&tm, "%x")
    stream >> std::get_time(&tm, "%x")

    Soll ein Datum in einen stringstream ausgegeben werden und umgekehrt wieder eingelesen werden. Das Ausgeben klappt, das Einlesen nicht, obwohl locale und format string identisch sind. (Auf Ideone klappt anscheinend beides, aber ich meine glaube nur mit std::locale(""), welches bei meinem OS glaube ich so etwas wie de_ch ist).

    Edit: Also std::get_time füllt die std::tm struct nur bis tm_mday aus, nachher nicht mehr. Und glaube ein failbit wird gesetzt, also fail() vom stringstreamgibt trueaus.

    Habe versucht es weiter auszubessern und nochmals auf Ideone den Fehler zu reproduzieren. Also eben mit Ideone funktioniert es soweit. Ideone hat aber ein anderes locale mit stream.imbue(std::locale("")).

    #include <iostream>
     
    #define BOOST_DATE_TIME_NO_LIB
    #include <boost/date_time.hpp>
     
    #include <sstream>
    #include <locale>
    #include <ctime>
    #include <iomanip>
     
    boost::gregorian::date DateFromString(const std::string& variable);
     
    int main() 
    {
     
    	DateFromString("01/09/2020");
     
     
    	return 0;
    }
     
    boost::gregorian::date DateFromString(const std::string& variable)
    {
    	std::stringstream stream;
    	stream.imbue(std::locale(""));
    	stream << variable;
     
    	bool streamCheck = stream.fail();
     
    	std::tm datetm = {0};
    	stream >> std::get_time(&datetm, "%x");
     
    	std::cout << datetm.tm_mday << '\n' << datetm.tm_mon << '\n' << datetm.tm_year << '\n';
     
    	boost::gregorian::date datevalue;
     
    	if (!stream.fail()) 
    	{
    		datevalue = boost::gregorian::date_from_tm(datetm);
    	}
    	else 
    	{
    		datevalue = boost::gregorian::date(boost::date_time::not_a_date_time);
    	}
     
    	return datevalue;
    }
    

    Also in der Referenz en.cppreference.com/w/cpp/locale/locale hat es bei den Examples:

     std::wcout << "User-preferred locale setting is " << std::locale("").name().c_str() << '\n';
    

    wobei User-preferred locale setting is en_US.UTF8 als possible output angegeben ist. Drücke ich auf run steht User-preferred locale setting is C. Wähle ich clang (C++14) steht nichts mehr, nichts mehr steht auch, wenn ich dies lokal auf meinem Computer ausprobiere.

    Unter en.cppreference.com/w/cpp/locale/time_get/get_date steht

    1. Reads successive characters from the sequence [beg, end) and parses out the calendar date value using the default format expected by this locale, which is the same format as

    "%x"

    (until C++11)

    "%d/%m/%y", "%m/%d/%y", "%y/%m/%d", and "%y/%d/%m", depending on date_order()

    (since C++11)

    as used by the functions std::get_time(), get(), and the POSIX function strptime()

    Das "%x" wird seit C++11 überschrieben 🙋🏻♂ ? Aber auch das Trennzeichen (/) ist ja anders?



  • Tag 3: Versuchte noch das Trennzeichen zu vereinheitlichen:

    for (size_t index = 0; index < date_string.size(); ++index)
    {
    	if (!std::isdigit(date_string[index]))
    	{
    		date_string[index] = '/';
    	}
    }
    

    und dann über std::time_get date_order die richtige Reihenfolge der Anordnung von Tag, Monat, Jahr zu finden. Bekam aber falsche Reihenfolgen, obwohl es bei time_put aufgrund desselben locals die Reihenfolge (und eigentlich auch das Trennzeichen) ausgab.

    Dafür hat es auf der verlinkten Website bei den Examples ein Link zu einem Bug. Dort ist eine library https://github.com/HowardHinnant/date in einem Kommentar verlinkt. Habe es mir noch nicht genau angeschaut, aber ich finde es sieht vielversprechend aus.

    Edit: Anscheinend übernimmt die library die bugs von std::time_get week_day_parse_bug.

    date::year_month_day date;
    std::stringstream istrm(date_string);
    istrm >> date::parse("%x", date);
    std::cout << "parsed date " << date << '\n';
    

    parse hätte es, funktionierte bei mir aber nicht mit std::locale::global(std::locale(""));.



  • Werde einen Trick anwenden. Da std::put_time(&tm, "%x") funktioniert, übergebe ich ein Datum mit voneinander unterschiedlichen Ziffern, also 23.04.1999. Aus dem string kann ich dann Reihenfolge und Trennzeichen auslesen.


Log in to reply