April 6, 2026
bsl::format for bdlt value types
bdlt value types are now supported by bsl::format. bsl::format
is more concise than streaming via ostream, and more type-safe and
high-level than output via printf.
bsl::format is similar to printf in that output is controlled by a
format string, where formatting one variable is controlled by a substring
enclosed by “{}”. format returns a bsl::string by value. The
substring “{}” itself means to format the value identically to streaming it to
an ostream.
bdlt::Date DATE(1776, 7, 4);
bdlt::Time TIME(16, 45, 21, 123, 456);
const bsl::string& a = bsl::format("{}, {}", DATE, TIME);
will set a to "04JUL1776, 16:45:21.123456".
For more detailed formatting, following the ‘{’ with a ‘:’, and then various ‘%’ sequences allows one to specify the whole field or parts of it. A small subset of ‘%’ sequences is:
“%D” – date like streaming to
ostream“%T” – time like streaming to
ostream“%i” – formats any
bdltvalue type in Iso8601 format“%b” – 3-letter abbreviation of month
“%d” – day of month
“%H” – hour (00 - 24)
“%I” – hour (01 - 12)
“%M” – minute (00 - 59)
“%S” – second (including fraction)
“%p” – “AM” or “PM”
“%z” – time zone as 2-digit hours and 2 digit minutes
const bsl::string& b = bsl::format("{:%D}, {:%T}, {:%i} & {:%i}",
DATE, TIME, (DATE + 2), TIME);
const bsl::string& c = bsl::format("{:%I:%M %p} on {:%b %d}", TIME, DATE);
will set b to "04JUL1776, 16:45:21.123456, 1776-07-06 & 16:45:21.123",
and c to "04:45 PM on JUL 04".
Note that all of the above sequences will also work for a Datetime or
DatetimeTz. While “%i” has an individual meaning for each bdlt value
type, all other ‘%’ sequences have the same meaning across bdlt. For
example:
bdlt::DatetimeTz DATETIMETZ(bdlt::Datetime(DATE, TIME), 300);
const bsl::string& d = bsl::format("{:%I:%M %p on %b %d}", DATETIMETZ);
will produce a value of d that exactly matches c above.
Between the opening ‘:’ and the first ‘%’ in a “{}” sequence, modifiers may occur. For example, a period followed by an unsigned integral value specifies the number of fractional digits of a second that are to be formatted, and a ‘:’ indicates that the hours and minutes of a time zone are to be separated by a ‘:’.
const bsl::string& e = bsl::format( "{:%T%z}", DATETIMETZ);
const bsl::string& f = bsl::format("{:.2:%T%z}", DATETIMETZ);
will set e to "16:45:21.123456+0500" and f to
"16:45:21.12+05:00".
Text that is not interpreted by format will be echoed to the output string
without modification if it occurs outside of “{}” sequences or after the first
‘%’ sequence within a “{}” sequence, but such text occurring between the opening
‘:’ of a “{}” sequence and the first ‘%’ character will result in an error.
It is also an error to specify a ‘%’ sequence that does not apply to the type being formatted.
All such errors result in compile-time errors in C++20 or later, and in exceptions thrown at run-time in C++17 or earlier.
To format a bdlt type, it is necessary to include the
file bdlt_<type>formatter.h, where <type> is the value type being
formatted. For example, formatting a Date
requires bdlt_dateformatter.h and formatting a DatetimeTz
requires bdlt_datetimetzformatter.h. So the examples above would require
#include <bdlt_date.h>
#include <bdlt_dateformatter.h>
#include <bdlt_time.h>
#include <bdlt_timeformatter.h>
#include <bdlt_datetimetz.h>
#include <bdlt_datetimetzformatter.h>
For a more thorough example, see the [bdlt_formatdoc component]