![]() |
One problem I seem to have struggled with in a number of projects is sticking the date and time in a file, usually to do some logging. My previous solution went something like this:
ofstream fout("logfile.txt"); // or any other stream
char tstr[SOME_MAX];
time_t now = time(0);
strcpy(tstr, ctime(now));
tstr(strlen(tstr)-1) = 0; // chop off the trailing \n
fout << tstr;
The problem with this solution is that it "felt" like a hack. I really wanted to find a way to do this using standard ostreams, without having to screw around with the \n, in seamless way. Why shouldn't I be able to write something like this and have it work:
ofstream fout("logfile.txt"); // or any other stream
time_t now = time(0);
fout << *localtime(&now);
Ideally, I wanted my solution to not only output the date & time, but do it using the user's locale. After doing a bit of net spelunking, I came across http://www.cantrip.org, which has a great discussion on using locales. That led me to this solution:
template<class charT, class traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT,traits>& os,
const std::tm& date)
{
typedef std::ostreambuf_iterator<charT,traits> outIter_t;
typedef std::time_put<charT, outIter_t> Facet;
// makes this safe in a multithreaded environment
std::basic_ostream<charT, traits>::sentry cerberus(os);
if ( cerberus )
{
// output the date & time, plus weekday and
// AM/PM indicator, in the local format
static const char format[] = "%a %x %X %p";
const Facet& fac = std::use_facet<Facet>(os.getloc());
if ( fac.put(os, os, os.fill(), &date, format, format + 11).failed() )
{
os.setstate(os.badbit);
}
}
return os;
}This solution works great on standard conforming compilers. On MSVC6, it chokes. A solution that works is:
template<class charT, class traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT,traits>& os,
const tm& date)
{
typedef std::ostreambuf_iterator<charT,traits> outIter_t;
typedef std::time_put<charT, outIter_t> Facet;
// makes this safe in a multithreaded environment
std::basic_ostream<charT, traits>::sentry cerberus(os);
if ( cerberus )
{
// output the date & time, plus weekday and AM/PM
// indicator, in the local format; note that the
// simpler version of put (std version above)
// doesn't work in MSVC
static const char format[] = "%a %x %I:%M:%S %p";
const Facet& fac = std::_USE(os.getloc(), Facet);
if ( fac.put(os, os, &date, format, format + 17).failed() )
{
os.setstate(os.badbit);
}
}
return os;
}One bit I've omitted from the code snips above is that it's a good idea to imbue the output stream with the desired locale, or at least with the default like so:
ofstream fout("logfile.txt");
fout.imbue( locale("") );
So now, with a little help from the preprocessor, I can stream out the date and time just like any other piece of data, and using the local format, to boot.
For those who are interested, here's the complete file, streamext.h.
| Latest Releases |
| Webifier 1.1.0 - 11/14/2007 - Show your pictures to the world with this web photo gallery creator. |
| PictureSaver 4.2.5 - 03/10/2006 - Turn your pictures into a slideshow screensaver; great with digital cameras! |
| RandomSaver 2.0.3 - 06/14/2002 - Got a lot of screen savers? Why watch just one? RandomSaver lets you watch 'em all! |
| GullBlaster 1.1 - 05/12/2002 - Tired of them seagulls? Now you can get even! Blast them before they blast you! |
| FontViewer 1.1.1 - 06/13/2002 - Preview all the installed fonts on your system. |
| Monitor page for changes |
|
powered by ChangeDetection |