+2  A: 

efotinis found a good way using from_stream .


I've looked into the manual of date_time and found it supports facets:

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
#include <sstream>
#include <locale>

int main() {
    using namespace boost::gregorian;

    std::wstringstream ss;
    wdate_input_facet * fac = new wdate_input_facet(L"%Y-%m-%d");
    ss.imbue(std::locale(std::locale::classic(), fac));

    date d;
    ss << L"2004-01-01 2005-01-01 2006-06-06";
    while(ss >> d) {
        std::cout << d << std::endl;
    }
}

You could also go with that.


I've looked up how date facets work:

  • The boost::date_time::date_input_facet template implements a facet.
  • Facets are derived from std::locale::facet and every one has an unique id.
  • You can imbue a new locale into a stream, replacing its old locale. The locale of a stream will be used for all sorts of parsing and conversions.
  • When you create a new std::locale using the form i showed, you give it an existing locale, and a pointer to facet. The given facet will replace any existing facet of the same type in the locale given. (so, it would replace any other date_input_facet used).
  • All facets are associated with the locale somehow, so that you can use std::has_facet<Facet>(some_locale) to check whether the given locale has some given facet type.
  • You can use a facet from one locale by doing std::use_facet<Facet>(some_locale).some_member... .
  • date_input_facet has a function get, which can be used like this:

The below is essentially done by operator>> by boost::date_type :

// assume src is a stream having the wdate_input_facet in its locale. 
// wdate_input_facet is a boost::date_time::date_input_facet<date,wchar_t> typedef.

date d;

// iterate over characters of src
std::istreambuf_iterator<wchar_t> b(src), e;

// use the facet to parse the date
std::use_facet<wdate_input_facet>(src.getloc()).get(b, e, src, d);
Johannes Schaub - litb
Thanks. "If you are sure ... " Yes. Your code is certainly clearer and terser! Is it more efficient?
ravenspoint
It gets rid of the compiler warning! ( You fooled it :-)
ravenspoint
It seems odd to me that the compiler rejects string( wstring(L"test") ) but accepts without complaint wstring ws(L"test"); string(ws.begin(), ws.end()) ). The effect is the same.
ravenspoint
string( wstring(L"test") ) vs. wstring ws(L"test"); string(ws.begin(), ws.end()) ) is very different. the effect of the second is that each character of ws is converted into string::char_type and then added. the first is just copy construction
Johannes Schaub - litb
i'm not sure whether you would notice any performance difference between my first method and yours though.
Johannes Schaub - litb
I think I preferred your earlier solution. I have never heard of a "facet".
ravenspoint
I have found the "facet" tutorial page. Looks interesting.
ravenspoint
yeah i removed the other one, since efotinis found the right way to do it with a from_* function (i should have looked in the "references" page, instead in the general overview page of date_time :))
Johannes Schaub - litb
if you want to use a format not supported by from_stream, you should really use facets, as they seem to be quite flexible
Johannes Schaub - litb
Unfortunately, the tutorial is tough going. Perhaps you could re-write your example so that it is more obvious how to use it inside a loop that handles a million inputs? Copying them all into a wstringstream first is not going to fly.
ravenspoint
you mean you get a vector of std::wstring and you want to return a vector of boost::gregorian::date ?
Johannes Schaub - litb
Yes. I believe I have it - see last part of the edited question at the top.
ravenspoint
Thanks for the extra information about facets. I confess, my eyes glazed over when I read it. I will look at it tomorrow morning when I am fresh. In the meantime, I have implemented this in the production code, and it works! Thank you very much
ravenspoint
+1  A: 

You can use the from_stream parser function:

using boost::gregorian::date;
using boost::gregorian::from_stream;

std::wstring ws( L"2008/01/01" );
date d1(from_stream(ws.begin(), ws.end()));
std::cout << d1;  // prints "2008-Jan-01"
efotinis
This seems no better than using string( ws.begin(), ws.end() ) and seems to preclude using from_uk_string - which I need in the 'real' application.
ravenspoint