Using time_put and time_get from <locale>.

P

Peter Jansson

Dear group,

I have been struggling to get a simple program for inserting and
extracting std::tm objects to/from streams to work. The code below tries
to read a std::tm object from a std::istringstream but fails to do so,
could anybody see what is wrong with the code? (Output follows the code.)
I fear that I have not completely grasped how the time_getXXX methods
should be used in the operator<< ?

With best regards,
Peter Jansson




// ---- CODE BEGIN ---- //
#include <ctime>
#include <iostream>
#include <locale>
#include <sstream>
#include <string>
std::istream& operator>>(std::istream& s,struct std::tm& t);
std::eek:stream& operator<<(std::eek:stream& s,const struct std::tm& t);
int main()
{
struct std::tm t={0};
t.tm_year=2006-1900;
t.tm_mon=1-1;
t.tm_mday=14;
t.tm_hour=19;
t.tm_min=22;
t.tm_sec=0;
std::cout<<"Date-time at start: "<<t<<'\n';
std::string dateTimeString("1976-07-02 05:45:03");
std::cout<<"Date-time to read from a stream: "<<dateTimeString<<'\n';
std::istringstream iss(dateTimeString);
iss>>t;
std::cout<<"Date-time after reading from a stream: "<<t<<'\n';
std::cout<<"Should be: 1976-07-02 05:45:03\n";
return 0;
}
std::istream& operator>>(std::istream& s,struct std::tm& t)
{
using namespace std;
istream::sentry cerberos(s);
if(cerberos) {
ios_base::iostate err = ios::goodbit;
typedef istreambuf_iterator<char> ist;
ist from=ist(s),end=ist();
const time_get<char>& tg=use_facet< time_get<char> >(s.getloc());
tg.get_date(from,end,s,err,&t);
tg.get_time(from,end,s,err,&t);
// Or should something like the following 3 lines be used?
//tg.get_year(from,end,s,err,&t);
//tg.get_date(from,end,s,err,&t);
//tg.get_time(from,end,s,err,&t);
s.setstate(err);
}
return s;
}
std::eek:stream& operator<<(std::eek:stream& s,const struct std::tm& t)
{
using namespace std;
ostream::sentry cerberos(s);
if(cerberos) {
const char* fmt="%Y-%m-%d %H:%M:%S";
use_facet< time_put<char> >(s.getloc()).put(s,s,s.fill(),&t,fmt,fmt+17);
}
return s;
}
// ---- CODE BEGIN ---- //
// ---- SAMPLE OUTPUT BEGIN ---- //
Date-time at start: 2006-01-14 19:22:00
Date-time to read from a stream: 1976-07-02 05:45:03
Date-time after reading from a stream: 2006-01-14 19:22:00
Should be: 1976-07-02 05:45:03
// ---- SAMPLE OUTPUT END ---- //
 
T

TB

Peter Jansson sade:
Dear group,

I have been struggling to get a simple program for inserting and
extracting std::tm objects to/from streams to work. The code below tries
to read a std::tm object from a std::istringstream but fails to do so,
could anybody see what is wrong with the code? (Output follows the code.)
I fear that I have not completely grasped how the time_getXXX methods
should be used in the operator<< ?

With best regards,
Peter Jansson




// ---- CODE BEGIN ---- //
std::string dateTimeString("1976-07-02 05:45:03");
std::istream& operator>>(std::istream& s,struct std::tm& t)
{
using namespace std;
istream::sentry cerberos(s);
if(cerberos) {
ios_base::iostate err = ios::goodbit;
typedef istreambuf_iterator<char> ist;
ist from=ist(s),end=ist();
const time_get<char>& tg=use_facet< time_get<char> >(s.getloc());
tg.get_date(from,end,s,err,&t);
tg.get_time(from,end,s,err,&t);
// Or should something like the following 3 lines be used?
//tg.get_year(from,end,s,err,&t);
//tg.get_date(from,end,s,err,&t);
//tg.get_time(from,end,s,err,&t);
s.setstate(err);
}
return s;
}
<snip>

Maybe I'm not remembering this frameset correctly, but shouldn't
'from' and 'end' isolate the specified range for each parsing.
i.e.
For tg.get_date() 'from' should be index 0, and 'end' should be index 10.
For tg.get_time() 'from' should be index 11 and 'end' should be index 19.
Otherwise the parsing fails and nothing is put in 't'.

TB
 
P

Peter Jansson

TB said:
Peter Jansson sade:






<snip>

Maybe I'm not remembering this frameset correctly, but shouldn't
'from' and 'end' isolate the specified range for each parsing.
i.e.
For tg.get_date() 'from' should be index 0, and 'end' should be index 10.
For tg.get_time() 'from' should be index 11 and 'end' should be index 19.
Otherwise the parsing fails and nothing is put in 't'.

TB

Yes, the methods parse the input using the iterators over the range
(from,end] but how can we specify that range using istreambuf_iterator?
tg.get_date(from,from+10,...) obviously does not work since +10 is not
defined...

Regard,
Peter Jansson
 
T

TB

Peter Jansson sade:
TB said:
Peter Jansson sade:
<snip>

Maybe I'm not remembering this frameset correctly, but shouldn't
'from' and 'end' isolate the specified range for each parsing.
i.e.
For tg.get_date() 'from' should be index 0, and 'end' should be index 10.
For tg.get_time() 'from' should be index 11 and 'end' should be index 19.
Otherwise the parsing fails and nothing is put in 't'.

TB

Yes, the methods parse the input using the iterators over the range
(from,end] but how can we specify that range using istreambuf_iterator?
tg.get_date(from,from+10,...) obviously does not work since +10 is not
defined...

Here comes a modified version of your code. First you need to find out
in what order dates are represented on your system, easily done with:

int main() {
const std::time_get said:
>(std::cin.getloc());
switch(tg.date_order()) {
case std::time_base::no_order:
std::cout<<"no\n"; break;
case std::time_base::dmy:
std::cout<<"dmy\n"; break;
case std::time_base::mdy:
std::cout<<"mdy\n"; break;
case std::time_base::ymd:
std::cout<<"ymd\n"; break;
case std::time_base::ydm:
std::cout<<"ydm\n"; break;
}
return 0;
}

On my system/loc it's "mdy". Then change your date string accordingly:
std::string dateTimeString("7/2/1976 05:45:03");

And with a few changes, this works for me:

std::istream& operator>>(std::istream& s,struct std::tm& t)
{
using namespace std;
istream::sentry cerberos(s);
if(cerberos) {
ios_base::iostate err = ios::goodbit;
typedef istreambuf_iterator<char> ist;
const time_get<char>& tg=use_facet< time_get<char> >(s.getloc());
ist from(s), end;
tg.get_date(from,end,s,err,&t);
++from;
tg.get_time(from,end,s,err,&t);
s.setstate(err);
}
return s;
}

TB
 
P

Peter Jansson

Here comes a modified version of your code. First you need to find out
in what order dates are represented on your system, easily done with:

int main() {

switch(tg.date_order()) {
case std::time_base::no_order:
std::cout<<"no\n"; break;
case std::time_base::dmy:
std::cout<<"dmy\n"; break;
case std::time_base::mdy:
std::cout<<"mdy\n"; break;
case std::time_base::ymd:
std::cout<<"ymd\n"; break;
case std::time_base::ydm:
std::cout<<"ydm\n"; break;
}
return 0;
}

On my system/loc it's "mdy". Then change your date string accordingly:
std::string dateTimeString("7/2/1976 05:45:03");

And with a few changes, this works for me:

std::istream& operator>>(std::istream& s,struct std::tm& t)
{
using namespace std;
istream::sentry cerberos(s);
if(cerberos) {
ios_base::iostate err = ios::goodbit;
typedef istreambuf_iterator<char> ist;
const time_get<char>& tg=use_facet< time_get<char> >(s.getloc());
ist from(s), end;
tg.get_date(from,end,s,err,&t);
++from;
tg.get_time(from,end,s,err,&t);
s.setstate(err);
}
return s;
}

TB

Thank you TB for your answer to my struggle!

I had to modify also the operator<< method to insert the std::tm using the
format the of current locale: 'x' and 'X' and with ++from the code works
fine, again: Thanks! Below is the full code I ended up with.

Best regards,
Peter Jansson


#include <cstdlib>
#include <ctime>
#include <iostream>
#include <locale>
#include <sstream>
#include <string>
std::istream& operator>>(std::istream& s,struct std::tm& t);
std::eek:stream& operator<<(std::eek:stream& s,const struct std::tm& t);
int main()
{
std::cout<<"Determining date order: ";
const std::time_get<char>& tg=std::use_facet< std::time_get<char> >(std::cin.getloc());
switch(tg.date_order()) {
case std::time_base::no_order:
std::cout<<"no order"; break;
case std::time_base::dmy:
std::cout<<"dmy"; break;
case std::time_base::mdy:
std::cout<<"mdy"; break;
case std::time_base::ymd:
std::cout<<"ymd"; break;
case std::time_base::ydm:
std::cout<<"ydm"; break;
}
std::cout<<'\n';
struct std::tm t={0};
t.tm_year=2006-1900;
t.tm_mon=1-1;
t.tm_mday=14;
t.tm_hour=19;
t.tm_min=22;
t.tm_sec=0;
std::cout<<"Date-time at start: "<<t<<'\n';
struct std::tm t2={0};
t2.tm_year=1986-1900;
t2.tm_mon=7-1;
t2.tm_mday=2;
t2.tm_hour=5;
t2.tm_min=45;
t2.tm_sec=3;
std::eek:stringstream t2s; t2s<<t2;
std::string dateTimeString(t2s.str());
std::cout<<"Date-time to read from a stream: "<<dateTimeString<<'\n';
std::istringstream iss(dateTimeString);
iss>>t;
std::cout<<"Date-time after reading from a stream: "<<t<<'\n';
return EXIT_SUCCESS;
}
std::istream& operator>>(std::istream& s,struct std::tm& t)
{
using namespace std;
istream::sentry cerberos(s);
if(cerberos) {
ios_base::iostate err = ios::goodbit;
typedef istreambuf_iterator<char> ist;
ist from(s),end;
const time_get<char>& tg=use_facet< time_get<char> >(s.getloc());
ist last=tg.get_date(from,end,s,err,&t);
++from;
tg.get_time(from,end,s,err,&t);
s.setstate(err);
}
return s;
}
std::eek:stream& operator<<(std::eek:stream& s,const struct std::tm& t)
{
using namespace std;
ostream::sentry cerberos(s);
if(cerberos) {
const time_put<char>& tp=use_facet< time_put<char> >(s.getloc());
tp.put(s,s,s.fill(),&t,'x');
s<<s.fill();
tp.put(s,s,s.fill(),&t,'X');
}
return s;
}
 
T

TB

Peter Jansson sade:
std::eek:stream& operator<<(std::eek:stream& s,const struct std::tm& t)
{
using namespace std;
ostream::sentry cerberos(s);
if(cerberos) {
const time_put<char>& tp=use_facet< time_put<char> >(s.getloc());
tp.put(s,s,s.fill(),&t,'x');
s<<s.fill();
tp.put(s,s,s.fill(),&t,'X');
}
return s;
}

Hm, I accidently ignored that function. No need to bother with
> std::eek:stringstream t2s; t2s<<t2;
> std::string dateTimeString(t2s.str());
> std::cout<<"Date-time to read from a stream:
> "<<dateTimeString<<'\n';
> std::istringstream iss(dateTimeString);
> iss>>t;

You could alway just do:

std::stringstream sstrm;
sstrm << t2;
std::cout<<sstrm.str();
sstrm >> t;

Lycka Till.

TB
 
P

Peter Jansson

Hm, I accidently ignored that function. No need to bother with


You could alway just do:

std::stringstream sstrm;
sstrm << t2;
std::cout<<sstrm.str();
sstrm >> t;

Lycka Till.

TB

Hej,

I assume I "could always just do" those last lines if I have defined the
operator<< and operator>> for std::tm?

I also noted that the global locale gets set to the classic "C" locale
upon program startup so I had to set it to the user defined default;
std::locale("") and imbue that locale on std::cout since the standard
streams are also created before main is called. The final (?) code is to
be found below.

Sincerely,
Peter Jansson
http://www.jansson.net/


#include <cstdlib>
#include <ctime>
#include <iostream>
#include <locale>
#include <sstream>
#include <string>
std::istream& operator>>(std::istream& s,struct std::tm& t);
std::eek:stream& operator<<(std::eek:stream& s,const struct std::tm& t);
int main()
{
using std::cout;
std::locale defloc("");
cout<<"Setting the global locale: "<<defloc.name()<<'\n';
cout.imbue(defloc);
cout<<"Locale of cout: "<<cout.getloc().name()<<'\n';
std::locale::global(defloc);
const std::time_t now=std::time(0),later2day5min(now+2*24*3600+5*60);
struct std::tm t=*localtime(&now),t2=*localtime(&later2day5min);
std::eek:stringstream t2s; t2s<<t2;
std::string dateTimeString(t2s.str());
std::istringstream iss(dateTimeString);
cout<<"Locale of ostringstream: "<<t2s.getloc().name()<<'\n';
cout<<"Locale of istringstream: "<<iss.getloc().name()<<'\n';
cout<<"Date order: ";
const std::time_get<char>&
tg=std::use_facet< std::time_get<char> >(cout.getloc());
switch(tg.date_order()) {
case std::time_base::no_order:
cout<<"no order"; break;
case std::time_base::dmy:
cout<<"dmy"; break;
case std::time_base::mdy:
cout<<"mdy"; break;
case std::time_base::ymd:
cout<<"ymd"; break;
case std::time_base::ydm:
cout<<"ydm"; break;
}
cout<<'\n';
cout<<"Date-time at start: "<<t<<'\n';
iss>>t;
cout<<"Date-time to read from a stream: "<<dateTimeString<<'\n';
cout<<"Date-time after reading from a stream: "<<t<<'\n';
return EXIT_SUCCESS;
}
std::istream& operator>>(std::istream& s,struct std::tm& t)
{
using namespace std;
istream::sentry cerberos(s);
if(cerberos) {
ios_base::iostate err = ios::goodbit;
const time_get<char>& tg=use_facet< time_get<char> >(s.getloc());
typedef istreambuf_iterator<char> ist;
ist from(s),end;
ist last=tg.get_date(from,end,s,err,&t);
++from;
tg.get_time(from,end,s,err,&t);
s.setstate(err);
}
return s;
}
std::eek:stream& operator<<(std::eek:stream& s,const struct std::tm& t)
{
using namespace std;
ostream::sentry cerberos(s);
if(cerberos) {
const time_put<char>& tp=use_facet< time_put<char> >(s.getloc());
const char fc(s.fill());
tp.put(s,s,fc,&t,'x');
s<<fc;
tp.put(s,s,fc,&t,'X');
}
return s;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,983
Messages
2,570,187
Members
46,747
Latest member
jojoBizaroo

Latest Threads

Top