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 diestd::tm
struct nur bistm_mday
aus, nachher nicht mehr. Und glaube einfailbit
wird gesetzt, alsofail()
vomstringstream
gibttrue
aus.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 stehtUser-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
- 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 mitstd::locale::global(std::locale(""));
.
-
Werde einen Trick anwenden. Da
std::put_time(&tm, "%x")
funktioniert, übergebe ich ein Datum mit voneinander unterschiedlichen Ziffern, also23.04.1999
. Aus dem string kann ich dann Reihenfolge und Trennzeichen auslesen.