• 12
• 14
• 13
• 10
• 11

# C++ locales and facets

This topic is 3823 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Does anybody use these obscure things? They're part of the standard library, but are apparently so bizarre that even the Josuttis book doesn't give a single working example of any of them. There's an example in MSDN but it may as well be written in Ancient Greek. All I want is to display a time in a locale-dependent way. I have the C functions that generate a struct tm with the time in, I have the line to generate a std::time_put facet, but then I have no idea how to use it. Ideas? :)

##### Share on other sites
No, not really. :) I saw that on Google. It's still largely inpenetrable to me. If I just want a string back from it, what do I do? Use an ostringstream? Some sort of back_inserter trick? It amazes me that they expect people to use this stuff.

##### Share on other sites
For the record, I hate and despise the C++ standard library localization components and strongly recommend using a third-party library for localization like ICU.

That being said, in order to use time_put::put(), you need a few things:

1) an output iterator where you want to write the time to. This can be anything from a std::ostream_iterator<CharType>, std::ostreambuf_iterator<CharType> or even a CharType *.

2) a CharType used for spacing. When inserting into an ostream os, this is typically os.fill(), which in turn is typically ' '.

3) a tm object containing the time to be outputted, which sounds like you've got covered.

4) a time format string. These are like printf() format strings, except time-specific. Time format string documentation usually comes under the strftime() documentation for your compiler's standard library. For just producing the a time string, you can use "%X". For a date-time string, "%c".

At this point you've got two choices of put() members. If your format string only consists of a single format character such as the "%X" or "%c" examples above, you can use either put() version.

The first is:
put(iter_type out, ios_base & str, char_type fill, const tm * t, const CharType * begin, const CharType * end)

Here out is the output iterator in (1). str is any stream object. It should be imbued with the same locale as the one you got your time_put facet from. It's used for the implementation to get a ctype<> facet from, but in many implementations this argument is ignored. fill is the fill character described in (2), t is your time in (3) and [begin, end) is the const CharType * range for your time format string in (4).

The second, the version for the single character time format string, is:
put(iter_type out, ios_base & str, char_type fill, const tm * t, char format, char modifier = 0)
If modifier is 0, then this form is equivalent to the first form with a format string of "%[format]". i.e. if format is 'X' then it's equivalent to "%X". If modifier is non-zero, them this form is equivalent to the first form with a format string of "%[modifier][format]". i.e. if format is 'X' and modifier is '#", then it's equivalent to a format string of "%#X". The C++ standard does not actually state what the effect of the modifier characters are; any modifiers characters are vendor-specific.

To string that all together into a form to get a std::string from a const std::tm * and a std::locale:
std::string format_time(const std::tm * time, const std::locale & loc) {  std::stringstream sstr;  sstr.imbue(loc);  typedef std::time_put<char> TimeFacet;  const TimeFacet & time_facet = std::use_facet<TimeFacet>(loc);  char format[] = "%x %X";  time_facet.put(sstr,                 sstr,                 sstr.fill(),                 time,                 format,                 format + sizeof(format));  return sstr.str();}

The one thing to note here, is that the type of output iterator is embedded in the type of the time_put<> facet, which defaults to std::ostreambuf_iterator<CharType>. If you wanted to use a different output iterator type, you'll need a different time_put facet.

##### Share on other sites
Ok, just one question - how does the stringstream get converted to an ostream_iterator for that first parameter? I thought you'd have to explicitly construct one yourself, but it builds fine without doing so, I find.

##### Share on other sites
As mentioned, the type of the output iterator is embedded in the time_put facet, so the type of the first argument to the put() function is set by the type of the time_put facet. For time_put<char> this is a std::ostreambuf_iterator<char>, which has a non-explicit single argument constructor of type std::ostream &. If time_put didn't embed the output iterator as part of the type, and had a templated output iterator argument like the vast majority of functions that take output iterators in the standard library, you would need to explicitly construct the ostreambuf_iterator (or ostream_iterator).

##### Share on other sites
Yeah, I was just having trouble following it because it says it takes an iterator, but every example I've seen supplies a stream, and it's been so long since I used a streambuf_iterator that it didn't occur to me that you could construct one from an ostream. Thanks.