C++ : convert date/time string to tm struct - c++

Consider this somewhat of a follow up to this question. Essentially, the C++ date/time formatting facilities seem to be hopelessly broken - so much so that in order to do something as simple as convert a date/time string into an object, you really have to resort to either Boost.Datetime or good old C strftime/strptime facilities.
The problem is that neither of these solutions work directly with the C++ locale settings imbued onto a particular iostream object. The C facilities use the global C/POSIX locale settings, whereas the I/O facilities in Boost.Datetime seem to bypass iostream locale settings entirely by allowing the user to directly set the names of months, weekdays, etc., regardless of locale.
So, I wanted something that would respect the locale settings imbued onto a particular I/O stream that would allow me to convert a string into a struct tm. It seemed easy enough, but I ran into obstacles around every corner. At first, I noticed that some implementations of the STL provide a non-standard std::time_get::get function, so I decided to implement something similar. Basically, I would simply iterate over the format string and whenever I hit a format flag, I would use one of the time_get facilities (like get_monthname, get_weekday, get_year, etc.) to convert the input string into a struct tm. This seems easy enough, except each one of these functions requires an exact iterator range. You can't convert "Monday,", it has to be "Monday" exactly, or the conversion fails. Since the iterators have to be istreambuf_iterator, you can't simply scan ahead, because each increment changes the get position in the stream buffer. So, basically you have to first iterate over the stream, copying each character into another streambuffer, and then when you hit a delimiter (like a space or a comma), use the second streambuffer with the time_get facilities. It's literally as if the C++ designers went out of their way to make this as annoying as possible.
So, is there an easier solution? What do most C++ programmers do when they need to convert a date/time string to an object? Do we just have to use the C facilities, and lose the advantages that come along with different locale settings imbued on different iostream objects?

Boost uses the standard locale(s) by default; you don't have to bypass anything:
#include "boost/date_time/gregorian/gregorian.hpp"
#include <iostream>
#include <sstream>
#include <ctime>
int main(){
using namespace boost::gregorian;
std::locale::global(std::locale(""));
std::locale german("German_Germany");
std::locale french("French_France");
date d1(day_clock::local_day());
date d2;
std::stringstream ss("2002-May-01");
std::cout << "Mine: " << d1 << " | ";
ss >> d2;
std::cout << d2 << '\n';
std::cout.imbue(german);
std::cout << "Germany: " << d1 << " | ";
ss.imbue(german);
ss << "2002-Mai-01";
ss >> d2;
std::cout << d2 << '\n';
std::cout.imbue(french);
std::cout << "France: " << d1 << " | " << d2 << '\n';
std::tm t = to_tm(d1);
std::cout << "tm: " << asctime(&t);
}
(Those locale names are specific to Windows, of course.) Output:
Mine: 2010-Oct-28 | 2002-May-01
Germany: 2010-Okt-28 | 2002-Mai-01
France: 2010-oct.-28 | 2002-mai-01
tm: Thu Oct 28 00:00:00 2010

Why not use the C library? It's almost certainly available in your implementation, and it's well debugged and tested.
If it's lacking some feature, surely it's easier to make wrapper function which does the timezone work you desire.

I always try to use locale independent strings to serialize data. Makes life a lot easier.

Related

Which is the best way to print to the console in c++?

I have read three ways to print things to the console in c++ from various sources.
Using using namespace std; and then using cout (CodeBlocks Standard)
Not using the above and using std::cout and std::endl; (C++ Primer)
Using printf (HackerRank)
Which is preferred and why?
Number 2 with amendment. (std::cout and '\n')
Why?
Because you should avoid using namespace std. Source
(Among other reasons) Because cout is typesafe and printf is not. Source
std::endl will force a flush of the output buffer to the console. Unless you specifically want this to happen use << '\n' or << "...string\n". Source
Unless you really care about speed, both cout and printf are fine. If you want faster runtimes, here are a few pointers :
Use only printf with no cout. This will give more speed than using a mixture of printf and cout or just cout.
Or use only cout but add the following at the beginning of execution
ios_base::sync_with_stdio(false);cin.tie(NULL); . There are two separate streams for printf and cout and they are synchronized by default. Lot of running time is wasted due to this synchronisation. These two lines of code will stop the synchronisation, but take care that you don't use any printf if you add these lines, otherwise printing might happen in random order.
Do not use endl unless you want to flush the output buffer. Lots of endl can make the code slower. Use cout<<'\n'; instead.
these is my debugger code that during these 10 years of c++ working helped me.
std::ostream &debugRecord (const char* fileName, int lineNum, const char* funcName)
{
std::lock_guard<std::mutex> lock(streamMutex_);
return std::cout << "Thread # " << getCurrentThreadId() << " -- "
<< "(" << fileName << ":" << lineNum << "): " << funcName << std::endl;
}
Both your first points do basically the same thing. It's better practice to use std:: instead of using namespace std; as the latter pollutes the global namespace and can cause naming conflicts.
Something not mentioned is that you can selectively expose parts of a namespace with using <namespace>::<element>; (e.g. using std::cout;). It's still better practice to be verbose with your statements, but this option still isn't as bad as exposing the entire namespace.
printf isn't as safe as cout (the stream << operators do a good job of printing what you want), you ought to avoid it while starting out.
The answer depends a lot on what you want to do. For output which largely uses default formats cout is indeed preferred because of the type safety and because it's very intuitive.
If you want to heavily format your output though I can only recommend the surprisingly versatile and straight-forward printf because manipulators in cout are a pain. True: The printf format syntax, does, let's say, take some getting used to, but it's surely worth it. Just double check the format string, listen to the warnings of your compiler, and use the proper format specifiers e.g. for size_t and other system dependent data in order to stay portable.
There is also a boost facility for combining streams and printf style formatting, see https://stackoverflow.com/a/15106194/3150802, but I have never used it. Perhaps somebody can comment on its usability?

iomanip / fixed width persistence

Why does
#include <iostream>
#include <iomanip>
int main()
{
std::cout << std::fixed << std::setw(4) << std::setprecision(0);
std::cout << 4;
std::cout << 4;
}
print
" 44
(ignore the quote, it's just to get the formatting right)
and not
" 4 4
?
I thought that the iostream 'modifiers' persistent on the stream until they are explicitly changed/reset. I have a bunch of numbers I need to print with a certain prefix so that all fields have equal width; should I re-apply my modifiers every time I print one? Doesn't seem very efficient.
Unfortunately you've wandered into one of the areas of the standard that's a little archaic and seemingly without any overarching design goals.
This is undoubtedly historic as the iostreams library AFAIAA, was not originally part of the STL which is what became the standard library.
It's worth reading the notes on all std::ios_base members and the associated manipulators.
For example:
http://en.cppreference.com/w/cpp/io/ios_base/width
Some I/O functions call width(0) before returning, see std::setw (this results in this field having effect on the next I/O function only, and not on any subsequent I/O)
The exact effects this modifier has on the input and output vary between the individual I/O functions and are described at each operator<< and operator>> overload page individually.
Anticipating:
But that's just <insert expletive>!!!
A: yup.

C++ equivalent of printf() or formatted output

I am relatively new to the C++ world.
I know std::cout is used for console output in C++. But consider the following code in C :
#include<stdio.h>
int main(){
double dNum=99.6678;
printf("%.02lf",dNum);
//output: 99.67
return 0;
}
How do I achieve the similar formatting of a double type value upto 2 decimal places using cout in C++ ?
I know C++ is backward compatible with C. But is there a printf() equivalent in C++ if so, then where is it defined ?
This is what you want:
std::cout << std::fixed << std::setprecision(2);
std::cout << dNum;
and don't forget to :
#include <iostream>
#include <iomanip>
There is no equivalent. It is a pain using cout for formatted output.
All suggested solutions calling setprecision and similar are awfull when using long formats.
boost::format does not support some very nice features. Incompatibilities with printf. I still use printf because it is unbeatable.
If you want to use printf like formatting you should probably use snprintf (or build an allocating variant of that on top of that). Note that sprintf requires you to be able to guarantee that the result will not overrun the buffer you have to keep defined behaviour. With snprintf on the other hand can guarantee that it will not overrun the buffer since you specifiy the maximal number of characters that will be written to the string (it will instead truncate the output).
You could even build something that can directly be fed to an ostream on top of snprintf by automatically allocate the buffer and place in an object that on destruction free that memory. This in addition with a method to feed the object to an ostream would finish it off. Something like (with room for improvements):
struct Format {
char buf[999];
Format(fmt, ...) {
va_list ap;
va_start(fmt, ap);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
}
}
ostream& operator<< (ostream& os, Format const& str);
then you use this as:
cout << Format("The answer is %d", 42) << endl;
If you're using the GNU libraries you could of course use printf directly since cout and stdout are the same object then. Otherwise you should probably avoid mixing stdio and iostreams as there is no guarantee that these are synchronized with each other.
If you really want to reuse the same formatting techniques as in C, you may use Boost::format, which does exactly that:
cout << boost::format("%.02lf") % dNum;
But is there a printf() equivalent in C++ if so, then where is it defined?
There is a standards proposal P0645 to add a similar formatting facility to C++. In the meantime you can use the {fmt} library that implements this proposal and more:
#include <fmt/core.h>
int main()
fmt::print("{:.02f}", 99.6678);
}
P0645 and {fmt} use Python-like format string syntax which is similar to printf's but uses {} as delimiters instead of %.
Also the type information is preserved so you don't need l or other noisy specifiers.
Save your program as CPP and run it.
It runs and prints the answer.
Because C++ also has the printf() and scanf() like C.
You can also use sprintf in C++ to 'print' into a string and then cout that string. This strategy leverages your experience with printf-style formatting.
To output a value to the console using C++, you need the global ostream object cout and the << operator. endl is another global ostream object used as line break.
All are defined in the <iostream> header file. You can also use various formatting flags to control the presentation of the output...
#include<iostream>
using namespace std;
int main() {
double dNum = 99.6678;
cout << dNum;
cout.setf(ios::scientific, ios::floatfield); // format into scientific notation
cout << dNum;
cout.precision(8); // change precision
cout << dNum;
system("pause");
return 0;
}
The functional equivalent of your printf() call, using std::cout, is
std::cout << fixed << setprecision(2) << dNum;
It is necessary to #include <iomanip> and <iostream>.
The printf() equivalent in C++ is std::printf(), declared in <cstdio>.
Also, thanks to backward compatibility to C - specifically C++98 was required to maximise backward compatiblility to C89 - C's printf() declared in <stdio.h> is also available in C++. Note, however, that <stdio.h> is deprecated (tagged for removal from a future version of the C++ standard). Also, not all features of printf() introduced in C99 (the 1999 C standard) or later are necessarily supported in C++.

boost to_upper function of string_algo doesn't take into account the locale

I have a problem with the functions in the string_algo package.
Consider this piece of code:
#include <boost/algorithm/string.hpp>
int main() {
try{
string s = "meißen";
locale l("de_DE.UTF-8");
to_upper(s, l);
cout << s << endl;
catch(std::runtime_error& e){
cerr << e.what() << endl;
}
try{
string s = "composición";
locale l("es_CO.UTF-8");
to_upper(s, l);
cout << s << endl;
catch(std::runtime_error& e){
cerr << e.what() << endl;
}
}
The expected output for this code would be:
MEISSEN
COMPOSICIÓN
however the only thing I get is
MEIßEN
COMPOSICIóN
so, clearly the locale is not being taken into account. I even try to set the global locale with no success. What can I do?
In addition to the answer of Éric Malenfant -- std::locale facets works on single character. To get better result you may use std::wstring -- thus more characters would be converterd, but as you can see it is still not perfect (example ß).
I would suggest to give a try to Boost.Locale (new library for boost, not yet in boost), that does stuff
http://cppcms.sourceforge.net/boost_locale/docs/,
Especially see http://cppcms.sourceforge.net/boost_locale/docs/index.html#conversions that deals with the problem you are talking about.
std::toupper assumes a 1:1 conversion, so there is no hope for the ß to SS case, Boost.StringAlgo or not.
Looking at StringAlgo's code, we see that it does use the locale (Except on Borland, it seems). So, for the other case, I'm curious: What is the result of toupper('ó', std::locale("es_CO.UTF-8"))on your platform?
Writing the above makes me think about something else: What is the encoding of the strings in your sources? UTF8? In that case, std::toupper will see two code units for 'ó', so there is no hope. Latin1? In that case, using a locale named ".UTF-8" is inconsistent.
In the standard library there is std::toupper (which boost::to_upper uses) that operates on one character at a time.
This explains why the ß doesn't work. You didn't say which standard library and codepage you are using so I don't know why the ó didn't work.
What happens if you use wstring instead?
You can use boost::locale.
Here is an example.

Table layout using std::cout

How do I format my output in C++ streams to print fixed width left-aligned tables? Something like
printf("%-14.3f%-14.3f\n", 12345.12345, 12345.12345);
poducing
12345.123 12345.123
Include the standard header <iomanip> and go crazy. Specifically, the setw manipulator sets the output width. setfill sets the filling character.
std::cout << std::setiosflags(std::ios::fixed)
<< std::setprecision(3)
<< std::setw(18)
<< std::left
<< 12345.123;
You may also consider more friendly functionality provided by one of these:
Boost.Format (powerful, but very heavy, more time and memory allocations than other mentioned)
Loki.SafeFormat
FastFormat (relatively new, but blazing fast library, also type-safe unlike the others)
Writing from memory, but should be something along these lines:
// Dumb streams:
printf("%-14.3f%-14.3f\n", 12345.12345, 12345.12345);
// For IOStreams you've got example in the other answers
// Boost Format supports various flavours of formatting, for example:
std::cout << boost::format("%-14.3f%-14.3f\n") % a % b;
std::cout << boost::format("%1$-14.3f%2$-14.3f\n") % a % b;
// To gain somewhat on the performance you can store the formatters:
const boost::format foo("%1$-14.3f%2$-14.3f\n");
std::cout << boost::format(foo) % a % b;
// For the Loki::Printf it's also similar:
Loki::Printf("%-14.3f%-14.3f\n")(a)(b);
// And finally FastFormat.Format (don't know the syntax for decimal places)
fastformat::fmtln(std::cout, "{0,14,,<}{1,14,,>}", a, b);
Also, if you plan to stick with any of these formatting libraries, examine thoroughly their limitations in context of expressibility, portability (and other library dependency), efficiency, support of internationalisation, type-safety, etc.
You want to use stream manipulators:
http://www.deitel.com/articles/cplusplus_tutorials/20060218/index.html