[date_time] i/o formatting

Hi. I've used the date_time I/O using facets and found it too complicated. The thing that bothers me is that I need to use a facet to specify the format string (e.g "HH:MM:SS"). This is burdensome. IMO, using facets is fine for defining things which are really locale-related (and are mostly constant during the process lifetime) such as the month names in the local language. The format is not such a property and can often change throughout the application, and as such is much better handled using an I/O manipulator: cout << time_format("HH:MM:SS") << my_ptime << endl; or if this is impossible, then cout << time_io(my_ptime, "HH:MM:SS") << endl; which surely is possible. I think of specifying the format string as similar to specifying the printing precision of a float, or specifying that an integer should be printed as hex. These are provided as manipulators without the complexity of facets (which most users, including me, know very little about). BTW, this is not my original idea. I saw it in a post (don't remember by whom) in this mailing list a few months ago. Thanks, Yuval

On Sun, 26 Feb 2006 00:50:04 +0200, Yuval Ronen wrote
Hi. I've used the date_time I/O using facets and found it too complicated. The thing that bothers me is that I need to use a facet to specify the format string (e.g "HH:MM:SS"). This is burdensome. IMO, using facets is fine for defining things which are really locale-related (and are mostly constant during the process lifetime) such as the month names in the local language.
Of course the order of dates *is* locale related. Even in the current standard library there is information in date facet about ordering.
The format is not such a property and can often change throughout the application, and as such is much better handled using an I/O manipulator:
cout << time_format("HH:MM:SS") << my_ptime << endl;
or if this is impossible, then
cout << time_io(my_ptime, "HH:MM:SS") << endl;
Shouldn't we stick to the current set of format strings which is consistent with the current standards? cout << time_format("%H:%M:%s") << my_ptime << endl;
which surely is possible.
I think of specifying the format string as similar to specifying the printing precision of a float, or specifying that an integer should be printed as hex. These are provided as manipulators without the complexity of facets (which most users, including me, know very little about).
BTW, this is not my original idea. I saw it in a post (don't remember by whom) in this mailing list a few months ago.
Sure this would be nice and it has been discussed before. The i/o code is implemented in a way that should allow for this. Patches certainly accepted. Jeff

Jeff Garland wrote:
On Sun, 26 Feb 2006 00:50:04 +0200, Yuval Ronen wrote
cout << time_format("HH:MM:SS") << my_ptime << endl;
Shouldn't we stick to the current set of format strings which is consistent with the current standards?
cout << time_format("%H:%M:%s") << my_ptime << endl;
Yes, of course, you're right. My stupid mistake.
Sure this would be nice and it has been discussed before. The i/o code is implemented in a way that should allow for this. Patches certainly accepted.
I'll see if I have some free time for this, although I'm not optimistic :-( I just hope that when date_time is accepted to standard ("when" and not "if" :-) ), it will have format manipulators...

On Sun, 26 Feb 2006 10:58:21 +0200, Yuval Ronen wrote
Sure this would be nice and it has been discussed before. The i/o code is implemented in a way that should allow for this. Patches certainly accepted.
I'll see if I have some free time for this, although I'm not optimistic :-( I just hope that when date_time is accepted to standard ("when" and not "if" :-) ), it will have format manipulators...
My current proposal doesn't have manipulators. However, a recent post by Martin A. about the 'non-standardness' of the date-time facets (not const after imbue) may very well force this to happen in the proposal -- since you couldn't rely on facets to do this. And basically you're arguing that it's inconvenient anyway. In any case, the full breadth of requirements needs to be considered: time types, duration types, periods. I think we would need different manipulators for at least these classes of items -- and probably different manipulators for time types versus date types... Jeff

On 2/25/06, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
Shouldn't we stick to the current set of format strings which is consistent with the current standards?
cout << time_format("%H:%M:%s") << my_ptime << endl;
I'm a huge fan of strftime, but being built around "struct tm" it has no way of knowing about fractional seconds and so there are no %-escapes for formatting them. Do you have any thoughts on how a format might be expressed for ptime, which can clearly be used to carry a much higher resolution timestamp? -- Caleb Epstein caleb dot epstein at gmail dot com

On Sun, 26 Feb 2006 08:36:02 -0500, Caleb Epstein wrote
On 2/25/06, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
Shouldn't we stick to the current set of format strings which is consistent with the current standards?
cout << time_format("%H:%M:%s") << my_ptime << endl;
I'm a huge fan of strftime, but being built around "struct tm" it has no way of knowing about fractional seconds and so there are no %- escapes for formatting them. Do you have any thoughts on how a format might be expressed for ptime, which can clearly be used to carry a much higher resolution timestamp?
Yep, sure do :-) Here's a link to round 1 of my TR2 proposal (n1900) : http://www.crystalclearsoftware.com/libraries/date_time/proposal_v75/date_ti... These are the same ones in boost date-time. Specifically w.r.t. fractional seconds date-time uses %s to include seconds and fractional seconds and %S to be seconds only for all time_duration and ptime formatting. Finer grained control is allowed by using %f and %F which have different behaviors when the fractional seconds are 'zero'. The only thing this system doesn't allow you to control is the number of fractional digits to display which would need something like %2f. Some of these flags conflict with various 'native' versions of strftime, but most are extensions of the current standard. As for 'struct tm', it is clearly a problem. My recommendation for a replacement can be found here: http://www.crystalclearsoftware.com/libraries/date_time/proposal_v75/date_ti... except that there is a bug in that doc because fractional second count need to be a long at least and probably should be a unique type: //struct to represent elements of a point in time struct timepoint { year_type year; //32 bit unsigned integer -- range depends on calendar week_type month; //short integer 1-12 -- zero flags invalid short day_of_year; //short short day_of_week; //0-6 -- 0 == sunday short week_number; //1-53 - 0 indicates invalid short hours; //0-24 short minutes; //0-59 short seconds; //0-60 -- 60 is leap second frac_seconds_type fractional_seconds_count; short frac_seconds_resolution; //increments of 10 only }; Basically tm without the any of the text fields. This structure should be a able to drive all the needed formatting of dates and times. Note that different resolution time systems are supported. Jeff

On 2/26/06, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
//struct to represent elements of a point in time struct timepoint { year_type year; //32 bit unsigned integer -- range depends on calendar week_type month; //short integer 1-12 -- zero flags invalid short day_of_year; //short short day_of_week; //0-6 -- 0 == sunday short week_number; //1-53 - 0 indicates invalid short hours; //0-24 short minutes; //0-59 short seconds; //0-60 -- 60 is leap second frac_seconds_type fractional_seconds_count; short frac_seconds_resolution; //increments of 10 only };
So would "pow(10, frac_seconds_resolution )-1" be the maximum expected value of fractional_seconds_count (excepting perhaps leap-microseconds or something)? I think this could bear a little further explanation than just "increments of 10 only". Given that it is a short I assume its not the denominator itself, but the log10 of it. -- Caleb Epstein caleb dot epstein at gmail dot com

On Mon, 27 Feb 2006 10:41:40 -0500, Caleb Epstein wrote
On 2/26/06, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
//struct to represent elements of a point in time struct timepoint { year_type year; //32 bit unsigned integer -- range depends on calendar week_type month; //short integer 1-12 -- zero flags invalid short day_of_year; //short short day_of_week; //0-6 -- 0 == sunday short week_number; //1-53 - 0 indicates invalid short hours; //0-24 short minutes; //0-59 short seconds; //0-60 -- 60 is leap second frac_seconds_type fractional_seconds_count; short frac_seconds_resolution; //increments of 10 only };
So would "pow(10, frac_seconds_resolution )-1" be the maximum expected value of fractional_seconds_count
Right.
(excepting perhaps leap- microseconds or something)?
That won't be supported -- fortunately it isn't needed :)
I think this could bear a little further explanation than just "increments of 10 only". Given that it is a short I assume its not the denominator itself, but the log10 of it.
Well there's a good possibility that the concept isn't thought thru all the way since things aren't implemented this way currrently ;-) The original idea is that a 0 would indicate no fractional seconds, 10 would indicate a resolution of tenths of seonds, 100 hundreths of seconds, etc -- for which a short doesn't work. But I like your idea better -- perhaps fact_seconds_digits is clearer. BTW, (not so subtle request comming) I haven't received much detailed feedback on the proposal so I'd love someone with a critical eye to read and send me feedback ;-) Jeff

Jeff Garland wrote:
On Sun, 26 Feb 2006 00:50:04 +0200, Yuval Ronen wrote
Hi. I've used the date_time I/O using facets and found it too complicated. The thing that bothers me is that I need to use a facet to specify the format string (e.g "HH:MM:SS"). This is burdensome. IMO, using facets is fine for defining things which are really locale-related (and are mostly constant during the process lifetime) such as the month names in the local language.
Of course the order of dates *is* locale related. Even in the current standard library there is information in date facet about ordering.
I think the date order is a borderline case. In theory, yes, the order is locale-related and the date_facet can have methods like: void set_dmy_order(); void set_mdy_order(); In practice, however, when specifying the date format ("%Y-%m-%d", for example), this overrides the former order settings, so these settings don't have much (any?) useful usages. P.S: On your other post, you say that you might need to remove the facets for a whole different reason. If this happens, then you can ignore all this...

On Mon, 27 Feb 2006 16:43:45 +0200, Yuval Ronen wrote
Jeff Garland wrote:
On Sun, 26 Feb 2006 00:50:04 +0200, Yuval Ronen wrote
Hi. I've used the date_time I/O using facets and found it too complicated. The thing that bothers me is that I need to use a facet to specify the format string (e.g "HH:MM:SS"). This is burdensome. IMO, using facets is fine for defining things which are really locale-related (and are mostly constant during the process lifetime) such as the month names in the local language.
Of course the order of dates *is* locale related. Even in the current standard library there is information in date facet about ordering.
I think the date order is a borderline case. In theory, yes, the order is locale-related and the date_facet can have methods like:
void set_dmy_order(); void set_mdy_order();
In practice, however, when specifying the date format ("%Y-%m-%d", for example), this overrides the former order settings, so these settings don't have much (any?) useful usages.
Right. These methods are really used to support input formatting. My proposal calls for both input and output to be format based as it is currently in boost date-time.
P.S: On your other post, you say that you might need to remove the facets for a whole different reason. If this happens, then you can ignore all this...
No, I think you extrapolated my comment too far. I wasn't saying that the facets would be removed -- just augmented with manipulators so you didn't have to resort to facet changes just to change the format string. The facet still needs to be there to set the default ordering and other properties. It would remain the only way to replace the character strings associated with month and week names... Jeff

cout << time_format("HH:MM:SS") << my_ptime << endl;
Do you want the modifiers to replace the functionality in the facets or work together? If they replace the facet, how do specify the format if you don't have access to the stream as in lexical_cast, program options etc.

Martin Adrian wrote:
cout << time_format("HH:MM:SS") << my_ptime << endl;
Do you want the modifiers to replace the functionality in the facets or work together?
I'm not sure. It's possible that the format manipulators will come in addition to the format in the facet, or in place of it (the facet will no longer contain a format string). I can't say that I have a strong opinion on this matter. I'm really not an I/O expert. Of course if the chosen way is to have both, then the manipulator format overrides the facet format.
If they replace the facet, how do specify the format if you don't have access to the stream as in lexical_cast, program options etc.
It's doesn't matter. When you don't have access to the stream (as in lexical_cast, don't know about program_options), you can apply neither a facet, nor a manipulator, so there is no difference.

It's doesn't matter. When you don't have access to the stream (as in lexical_cast, don't know about program_options), you can apply neither a facet, nor a manipulator, so there is no difference.
By default all streams use the global locale. In my applications I add the date_time facets to the global locale at program startup so e.g. lexical_cast works fine. Of course it would be even better if lexcial_cast supported locales but it is better than nothing. If the facet default was the current locale ("%x") I would only need to add the facets when I need to parse dates.

Martin Adrian wrote:
It's doesn't matter. When you don't have access to the stream (as in lexical_cast, don't know about program_options), you can apply neither a facet, nor a manipulator, so there is no difference.
By default all streams use the global locale.
I didn't know that. You learn something new every day...

Christopher Cambly <ccambly@ca.ibm.com> writes:
David Abrahams <dave@boost-consulting.com> wrote on 02/25/2006 06:04:28 AM:
Hi Chris and Michael
I note at http://engineering.meta-comm.com/boost-regression/CVS- HEAD/developer/summary.html there are no results for VisualAge C++. We're generally reluctant to apply patches to support any given compiler if there isn't someone running tests, so we can verify that it makes things better and that we haven't introduced regressions. Michael told me in Lillehammer that y'all were running the tests with the results upload step disabled. If that's the case, you could just start uploading the results to us on a regular basis and it would be much easier to support your compiler.
Thanks,
-- Dave Abrahams Boost Consulting www.boost-consulting.com
Currently we are only running the Boost CVS line with our development line which is an unreleased compiler. IBM has a strict policy about publishing external(publicly viewable) numbers with unreleased compilers.
This is easily fixed. We can use our currently released V8 compiler for publishing results for the Boost CVS line. That said, our machine resources are at a premium. How often would we be required to provide results?
Just as an observation, the Boost results reporting system seems to change radically with each new release. I myself have not yet previewed the CVS line but from what Michael has told me it has undergone some changes yet again. We typically spend a fair amount of time debugging the Boost results reporting mechanism on our platforms. This can make our results reporting rather hit or miss... more often than not we seem to miss.
Chris, Please post your replies to the Boost list; some of your questions are not decideable by me alone. Thanks -- Dave Abrahams Boost Consulting www.boost-consulting.com

Yuval Ronen <ronen_yuval <at> yahoo.com> writes:
I think of specifying the format string as similar to specifying the printing precision of a float, or specifying that an integer should be printed as hex. These are provided as manipulators without the complexity of facets (which most users, including me, know very little about).
I don't agree with that comparison. Date formatting is more like the number formatting (decimal separator, grouping etc) which is part of the locale for numbers. Don't really see why you need manipulators. If you want to use the US date format do setlocale("US"), if you want German dates do setlocale("DE") etc. That is how you do it if you want numbers formatted and don't see why dates are any different. If you are writing an application that need to parse/print dates in a more generic matter use a facet just as you do to handle different decimal separators. Unfortunatly the above doesn't work in the boost::date_time library since it ignores the locale. A simple fix would be to let the default format be "%x" and "%c" so you only need to mess with the facets if you want something that isn't standard. For some standard library implementations it is also possible to make the setlocale work for parsing (e.g. libstd++ works fine while Dinkumware doesn't)

Don't really see why you need manipulators. If you want to use the US date format do setlocale("US"), if you want German dates do setlocale("DE") etc. That is how you do it if you want numbers formatted and don't see why dates are any different.
I don't want to use the "US", "German" or any other specific regional settings - I want to use *my* settings.
If you are writing an application that need to parse/print dates in a more generic matter use a facet just as you do to handle different decimal separators.
But this is just most inconvenient...
I think of specifying the format string as similar to specifying the printing precision of a float, or specifying that an integer should be printed as hex. These are provided as manipulators without the complexity of facets (which most users, including me, know very little about).
I don't agree with that comparison. Date formatting is more like the number formatting (decimal separator, grouping etc) which is part of the locale for numbers.
You have a point with the decimal separator issue (decimal separator as an example). After thinking about it some more, perhaps what I'm complaining about is something that is general in the locale/facet system. Maybe what's really bothering me is that once a certain setting is considered as "locale related", such as the decimal separator, it can only be configured using the locale/facet over-complicated way. But sometimes I don't want to use the "US", "German" or any other local setting for a decimal separator - I want to use *my* decimal separator. I souldn'd be forced to use a locale in such cases, IMO. IOW, I wish *all* settings would be configurable using manipulators (or an equivalent convenient way), and yes, that includes a decimal separator manipulator... The date_time I/O just brought all this to the surface, because setting a date/time format string is much more common than setting a decimal separator, but in principal it's the same thing...

Yuval Ronen wrote:
After thinking about it some more, perhaps what I'm complaining about is something that is general in the locale/facet system. Maybe what's really bothering me is that once a certain setting is considered as "locale related", such as the decimal separator, it can only be configured using the locale/facet over-complicated way. But sometimes I don't want to use the "US", "German" or any other local setting for a decimal separator - I want to use *my* decimal separator. I souldn'd be forced to use a locale in such cases, IMO. IOW, I wish *all* settings would be configurable using manipulators (or an equivalent convenient way), and yes, that includes a decimal separator manipulator...
I agree. This often happens when the program needs to output numbers or dates in a specific predefined format that is locale-independent (or that is locale-dependent but the locale information doesn't come in a form that C++ locales recognize, but as information about the required output format.)

Yuval Ronen <ronen_yuval <at> yahoo.com> writes:
After thinking about it some more, perhaps what I'm complaining about is something that is general in the locale/facet system. Maybe what's really bothering me is that once a certain setting is considered as "locale related", such as the decimal separator, it can only be configured using the locale/facet over-complicated way. But sometimes I don't want to use the "US", "German" or any other local setting for a decimal separator - I want to use *my* decimal separator. I souldn'd be forced to use a locale in such cases, IMO. IOW, I wish *all* settings would be configurable using manipulators (or an equivalent convenient way), and yes, that includes a decimal separator manipulator...
I use a set of facet helper classes. ss.imbue(add_facet(locale(), new number_format<char>(":"))); ss << 1.23; // output "1:23" ss.imbue(add_facet(locale::classic(), new number_format<char>(':', '_', "43"))); ss << 12345678.9; // output "1_234_5678:9" ss.imbue(add_facet(locale(), new stream_delimiter<char>(";\t"))); ss.str("123;String with spaces\t456"); int n1, n2; string s1; ss >> n1 >> s1 >> n2; // n1=123, n2=456, s1="String with spaces"
participants (6)
-
Caleb Epstein
-
Christopher Cambly
-
Jeff Garland
-
Martin Adrian
-
Peter Dimov
-
Yuval Ronen