// bdlt_iso8601util.h                                                 -*-C++-*-
#ifndef INCLUDED_BDLT_ISO8601UTIL
#define INCLUDED_BDLT_ISO8601UTIL

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide conversions between date/time objects and ISO 8601 strings.
//
//@CLASSES:
//  bdlt::Iso8601Util: namespace for ISO 8601 date/time conversion functions
//
//@SEE_ALSO: bdlt_iso8601utilconfiguration
//
//@DESCRIPTION: This component provides a namespace, 'bdlt::Iso8601Util',
// containing functions that convert 'bsls' timeinterval and 'bdlt' date, time,
// and datetime objects to and from ("generate" and "parse", respectively)
// corresponding string representations that are compliant with the ISO 8601
// standard.  The version of the ISO 8601 standard that is the basis for this
// component can be found at:
//..
//  http://dotat.at/tmp/ISO_8601-2004_E.pdf
//..
// In general terms, 'Iso8601Util' functions support what ISO 8601 refers to as
// *complete* *representations* in *extended* *format*.  We first present a
// brief overview before delving into the details of the ISO 8601
// representations that are supported for each of the relevant vocabulary
// types.
//
// Each function that *generates* ISO 8601 strings (named 'generate' and
// 'generateRaw') takes an object and a 'char *' buffer, 'bsl::string', or
// 'bsl::ostream', and writes an ISO 8601 representation of the object to the
// buffer, string, or stream.  The "raw" functions are distinguished from their
// non-"raw" counterparts in three respects:
//
//: o The length of the 'char *' buffer is not supplied to the 'generateRaw'
//:   functions.
//:
//: o The 'generateRaw' functions do not output a null terminator.
//:
//: o The 'generate' functions that provide an 'int bufferLength' parameter
//:   truncate the generated output to 'bufferLength' characters.  (Neither the
//:   'generateRaw' functions nor the 'generate' functions taking 'bsl::string'
//:   or 'bsl::ostream' do any truncation of their generated output.)
//
// Since the generate functions always succeed, no status value is returned.
// Instead, either the number of characters output to the 'char *' buffer or
// string, or a reference to the stream, is returned.  (Note that the
// generating functions also take an optional 'bdlt::Iso8601UtilConfiguration'
// object, which is discussed shortly.)
//
// Each function that *parses* ISO 8601 strings (named 'parse') take the
// address of a target object and a 'const char *' (paired with a 'length'
// argument) or 'bsl::string_view', and loads the object with the result of
// parsing the character string.  Since parsing can fail, the parse functions
// return an 'int' status value (0 for success and a non-zero value for
// failure).  Note that, besides elementary syntactical considerations, the
// validity of parsed strings are subject to the semantic constraints imposed
// by the various 'isValid*' class methods, (i.e., 'Date::isValidYearMonthDay',
// 'Time::isValid', etc.).
//
///Terminology
///-----------
// As this component concerns ISO 8601, some terms from that specification are
// used liberally in what follows.  Two ISO 8601 terms of particular note are
// *zone* *designator* and *fractional* *second*.
//
// An ISO 8601 *zone* *designator* corresponds to what other 'bdlt' components
// commonly refer to as a timezone offset (or simply as an offset; e.g., see
// 'bdlt_datetimetz').  For example, the ISO 8601 string
// '2002-03-17T15:46:00+04:00' has a zone designator of '+04:00', indicating a
// timezone 4 hours ahead of UTC.
//
// An ISO 8601 *fractional* *second* corresponds to, for example, the
// combined 'millisecond' and 'microsecond' attributes of a 'bdlt::Time'
// object, or the combined 'millisecond' and 'microsecond' attributes of a
// 'bdlt::Datetime' object.  For example, the 'Time' value (and ISO 8601
// string) '15:46:09.330000' has a 'millisecond' attribute value of 330 and a
// 'microsecond' attribute of 0 (i.e., a fractional second of .33).
//
///ISO 8601 String Generation
///--------------------------
// Strings produced by the 'generate' and 'generateRaw' functions are a
// straightforward transposition of the attributes of the source value into an
// appropriate ISO 8601 format, and are best illustrated by a few examples.
// Note that for 'Datetime' and 'DatetimeTz', the fractional second is
// generated with the precision specified in the configuration.  Also note that
// for 'Time' and 'TimeTz', the fractional second is generated with the
// precision specified in the configuration up to a maximum precision of 6.
//..
//  +--------------------------------------+---------------------------------+
//  |             Object Value             |    Generated ISO 8601 String    |
//  |                                      |  (using default configuration)  |
//  +======================================+=================================+
//  |  bsls::TimeInterval(1000, 3000000)   |  PT16M40.003S                   |
//  +--------------------------------------+---------------------------------+
//  |  Date(2002, 03, 17)                  |  2002-03-17                     |
//  +--------------------------------------+---------------------------------+
//  |  Time(15, 46, 09, 330)               |  15:46:09.330                   |
//  +--------------------------------------+---------------------------------+
//  |  Datetime(Date(2002, 03, 17)         |                                 |
//  |           Time(15, 46, 09, 330))     |  2002-03-17T15:46:09.330        |
//  +--------------------------------------+---------------------------------+
//  |  DateTz(Date(2002, 03, 17), -120)    |  2002-03-17-02:00 [*]           |
//  +--------------------------------------+---------------------------------+
//  |  TimeTz(Time(15, 46, 09, 330), 270)  |  15:46:09.330+04:30             |
//  +--------------------------------------+---------------------------------+
//  |  DatetimeTz(Datetime(                |                                 |
//  |              Date(2002, 03, 17),     |                                 |
//  |              Time(15, 46, 09, 330)), |                                 |
//  |             0)                       |  2002-03-17T15:46:09.330+00:00  |
//  +--------------------------------------+---------------------------------+
//..
// [*] Note that the ISO 8601 specification does not have an equivalent to
// 'bdlt::DateTz'.
//
///Configuration
///- - - - - - -
// The 'generate' and 'generateRaw' functions provide an optional configuration
// parameter.  This optional parameter, of type 'Iso8601UtilConfiguration',
// enables configuration of four aspects of ISO 8601 string generation:
//
//: o The decimal sign to use in fractional seconds: '.' or ','.
//:
//: o The precision of the fractional seconds.
//:
//: o Whether ':' is optional in zone designators.
//:
//: o Whether 'Z' is output for the zone designator instead of '+00:00' (UTC).
//
// 'Iso8601UtilConfiguration' has four attributes that directly correspond to
// these aspects.  In addition, for generate methods that are not supplied with
// a configuration argument, a process-wide configuration takes effect.  See
// 'bdlt_iso8601utilconfiguration' for details.
//
///ISO 8601 String Parsing
///-----------------------
// The 'parse' functions accept *all* strings that are produced by the generate
// functions.  In addition, the parse functions accept some variation in the
// generated strings, the details of which are discussed next.  Note that the
// parse methods are not configurable like the generate methods (i.e., via an
// optional 'Iso8601UtilConfiguration' argument).  Moreover, the process-wide
// configuration has no effect on parsing either.  Instead, the parse methods
// automatically accept '.' or ',' as the decimal sign in fractional seconds,
// and treat '+00:00', '+0000', 'Z', and 'z' as equivalent zone designators
// (all denoting UTC).
//
// The 'parseRelaxed' functions accept "relaxed" ISO 8601 format that is a
// superset of the strict ISO 8601 format, meaning this function will parse
// ISO 8601 values as well as supporting some common variations.  Currently
// this allows a SPACE character to be used as an alternative separator between
// date and time elements (where strict ISO 8601 requires a 'T'), but the set
// of extensions may grow in the future.
//
///Zone Designators
/// - - - - - - - -
// The zone designator is optional, and can be present when parsing for *any*
// type other than bsls::TimeInterval, i.e., even for 'Date', 'Time', and
// 'Datetime'.  If a zone designator is parsed for a 'Date', it must be valid,
// so it can affect the status value that is returned in that case, but it is
// otherwise ignored.  For 'Time' and 'Datetime', any zone designator present
// in the parsed string will affect the resulting object value (unless the zone
// designator denotes UTC) because the result is converted to UTC.  If the zone
// designator is absent, it is treated as if '+00:00' were specified:
//..
//  +------------------------------------+-----------------------------------+
//  |       Parsed ISO 8601 String       |        Result Object Value        |
//  +====================================+===================================+
//  |  2002-03-17-02:00                  |  Date(2002, 03, 17)               |
//  |                                    |  # zone designator ignored        |
//  +------------------------------------+-----------------------------------+
//  |  2002-03-17-02:65                  |  Date: parsing fails              |
//  |                                    |  # invalid zone designator        |
//  +------------------------------------+-----------------------------------+
//  |  15:46:09.330+04:30                |  Time(11, 16, 09, 330)            |
//  |                                    |  # converted to UTC               |
//  +------------------------------------+-----------------------------------+
//  |  15:46:09.330+04:30                |  TimeTz(Time(15, 46, 09, 330),    |
//  |                                    |         270)                      |
//  +------------------------------------+-----------------------------------+
//  |  15:46:09.330                      |  TimeTz(Time(15, 46, 09, 330),    |
//  |                                    |         0)                        |
//  |                                    |  # implied '+00:00'               |
//  +------------------------------------+-----------------------------------+
//  |  2002-03-17T23:46:09.222-05:00     |  Datetime(Date(2002, 03, 18),     |
//  |                                    |           Time(04, 46, 09, 222))  |
//  |                                    |  # carry into 'day' attribute     |
//  |                                    |  # when converted to UTC          |
//  +------------------------------------+-----------------------------------+
//..
// In the last example above, the conversion to UTC incurs a carry into the
// 'day' attribute of the 'Date' component of the resulting 'Datetime' value.
// Note that if such a carry causes an underflow or overflow at the extreme
// ends of the valid range of dates (0001/01/01 and 9999/12/31), then parsing
// for 'Datetime' fails.
//
///Fractional Seconds
/// - - - - - - - - -
// The fractional second is optional.  When the fractional second is absent, it
// is treated as if '.0' were specified.  When the fractional second is
// present, it can have one or more digits (i.e., it can contain more than
// six).  For 'Datetime', 'DatetimeTz', 'Time', and 'TimeTz', if more than six
// digits are included in the fractional second, values are rounded to a full
// microsecond; i.e., values greater than or equal to .5 microseconds are
// rounded up.  For 'bsls::TimeInterval', if more than nine digits are included
// in the fractional second, values are rounded to a full nanosecond; i.e.,
// values greater than or equal to .5 microseconds are rounded up.  These
// roundings may incur a carry of one second into the 'second' attribute:
//..
//  +--------------------------------------+---------------------------------+
//  |        Parsed ISO 8601 String        |      Result Object Value        |
//  +======================================+=================================+
//  |  15:46:09.1                          |  Time(15, 46, 09, 100)          |
//  +--------------------------------------+---------------------------------+
//  |  15:46:09-05:00                      |  TimeTz(Time(15, 46, 09, 000),  |
//  |                                      |         -300)                   |
//  |                                      |  # implied '.0'                 |
//  +--------------------------------------+---------------------------------+
//  |  15:46:09.99999949                   |  Time(15, 46, 09, 999, 999)     |
//  |                                      |  # truncate last two digits     |
//  +--------------------------------------+---------------------------------+
//  |  15:46:09.9999995                    |  Time(15, 46, 10, 000, 000)     |
//  |                                      |  # round up and carry           |
//  +--------------------------------------+---------------------------------+
//..
// Note that, for 'Datetime' and 'DatetimeTz', if a carry due to rounding of
// the fractional second would cause an overflow at the extreme upper end of
// the valid range of dates (i.e., 9999/12/31), then parsing would fail.
//
///Leap Seconds
/// - - - - - -
// Leap seconds are not representable by 'bdlt::Time' or 'bdlt::Datetime'.
// Hence, they are not produced by any of the 'Iso8601Util' generate functions.
// However, positive leap seconds *are* supported by the parse functions.  A
// leap second is recognized when the value parsed for the 'second' attribute
// of a 'Time' is 60 -- regardless of the values parsed for the 'hour',
// 'minute', 'millisecond', and 'microsecond' attributes.  Note that this
// behavior is more generous than that afforded by the ISO 8601 specification
// (which indicates that a positive leap second can only be represented as
// "23:59:60Z").
//
// When a leap second is detected during parsing of an ISO 8601 string, the
// 'second' attribute is taken to be 59, so that the value of the 'Time' object
// can be validly set; then an additional second is added to the object.  Note
// that the possible carry incurred by a leap second (i.e., when loading the
// result of parsing into a 'Datetime' or 'DatetimeTz' object) has the same
// potential for overflow as may occur with fractional seconds that are rounded
// up (although in admittedly pathological cases).
//
///The Time 24:00
/// - - - - - - -
// According to the ISO 8601 specification, the time 24:00 is interpreted as
// midnight, i.e., the last instant of a day.  However, this concept is not
// supported by 'bdlt'.  Although 24:00 is *representable* by 'bdlt', i.e., as
// the default value for 'bdlt::Time', 'Time(24, 0)' does *not* represent
// midnight when it is the value for the "time" attribute of a 'Datetime' (or
// 'DatetimeTz') object.  For example:
//..
//  bdlt::Datetime notMidnight =
//              bdlt::Datetime(bdlt::Date(2002, 03, 17), bdlt::Time(24, 0, 0));
//
//  notMidnight.addSeconds(1);
//  assert(notMidnight ==
//              bdlt::Datetime(bdlt::Date(2002, 03, 17), bdlt::Time( 0, 0, 1));
//..
// It is important to be aware of this peculiarity of 'Datetime' (and
// 'DatetimeTz') as it relates to ISO 8601.
//
// The following table shows some examples of parsing an ISO 8601 string
// containing "24:00".  Note that parsing fails if the zone designator is not
// equivalent to "+00:00" when the time 24:00 is encountered:
//..
//  +------------------------------------+-----------------------------------+
//  |       Parsed ISO 8601 String       |        Result Object Value        |
//  +====================================+===================================+
//  |  24:00:00.000000                   |  Time(24, 0, 0, 0)                |
//  |                                    |  # preserve default 'Time' value  |
//  +------------------------------------+-----------------------------------+
//  |  24:00:00.000000-04:00             |  TimeTz: parsing fails            |
//  |                                    |  # zone designator not UTC        |
//  +------------------------------------+-----------------------------------+
//  |  0001-01-01T24:00:00.000000        |  Datetime(Date(0001, 01, 01),     |
//  |                                    |           Time(24, 0, 0, 0))      |
//  |                                    |  # preserve 'Datetime' default    |
//  |                                    |  # value                          |
//  +------------------------------------+-----------------------------------+
//  |  2002-03-17T24:00:00.000000        |  Datetime(Date(2002, 03, 17),     |
//  |                                    |           Time(24, 0, 0, 0))      |
//  |                                    |  # preserve default 'Time' value  |
//  +------------------------------------+-----------------------------------+
//..
// An 'hour' attribute value of 24 is also "preserved" by the generate
// functions provided by this component:
//..
//  +------------------------------------+-----------------------------------+
//  |        Source Object Value         |     Generated ISO 8601 String     |
//  +====================================+===================================+
//  |  Time(24, 0, 0, 0)                 |  24:00:00.000                     |
//  +------------------------------------+-----------------------------------+
//  |  Datetime(Date(2002, 03, 17),      |  2002-03-17T24:00:00.000          |
//  |           Time(24, 0, 0, 0))       |                                   |
//  +------------------------------------+-----------------------------------+
//..
//
///Summary of Supported ISO 8601 Representations
///- - - - - - - - - - - - - - - - - - - - - - -
// The syntax description below summarizes the ISO 8601 string representations
// supported by this component.  Although not quoted (for readability),
// '[+-:.,TtZz]' are literal characters that can occur in ISO 8601 strings.
// Furthermore, for clarity, the (rarely used) lowercase 't' and 'z' characters
// are omitted from the specifications below, as well as from the
// function-level documentation.  The characters '[YMDhms]' each denote a
// decimal digit, '{}' brackets optional elements, '()' is used for grouping,
// and '|' separates alternatives:
//..
// <Generated Date>        ::=  <DATE>
//
// <Parsed Date>           ::=  <Parsed DateTz>
//
// <Generated DateTz>      ::=  <DATE><ZONE>
//
// <Parsed DateTz>         ::=  <DATE>{<ZONE>}
//
// <Generated Time>        ::=  <TIME FLEXIBLE>
//
// <Parsed Time>           ::=  <Parsed TimeTz>
//
// <Generated TimeTz>      ::=  <TIME FLEXIBLE><ZONE>
//
// <Parsed TimeTz>         ::=  <TIME FLEXIBLE>{<ZONE>}
//
// <Generated Datetime>    ::=  <DATE>T<TIME FLEXIBLE>
//
// <Parsed Datetime>       ::=  <Parsed DatetimeTz>
//
// <Generated DatetimeTz>  ::=  <DATE>T<TIME FLEXIBLE><ZONE>
//
// <Parsed DatetimeTz>     ::=  <DATE>T<TIME FLEXIBLE>{<ZONE>}
//
// <DATE>                  ::=  YYYY-MM-DD
//
// <TIME FLEXIBLE>         ::=  hh:mm:ss{(.|,)s+}  # one or more digits in the
//                                                 # fractional second
//
// <ZONE>                  ::=  (+|-)hh{:}mm|Z     # zone designator
//..
//
///Summary of Supported ISO 8601 Duration Representations
///- - - - - - - - - - - - - - - - - - - - - - -
// The syntax description below summarizes the ISO 8601 string representations
// for durations supported by this component.  Although not quoted (for
// readability), '[.,PWDTHMS]' are literal characters that can occur in ISO
// 8601 strings.  The characters '[wdhms]' each denote a decimal digit, '{}'
// brackets optional elements, '()' is used for grouping, and '|' separates
// alternatives:
//..
// <Date Duration>      ::=  {w+W}{d+D}
//
// <Time Duration>      ::=  T{h+H}{m+M}{s+{(.|,)s+}S}         # must contain
//                                                             # at least one
//                                                             # optional field
//                                                             # (i.e. "T" is
//                                                             # not valid)
//
// <Generated Duration> ::=  P<Date Duration><Time Duration>   # all values
//                                                             # guaranteed to
//                                                             # be less than
//                                                             # their modulus
//                                                             # (weeks can be
//                                                             # be up to 14
//                                                             # digits), and
//                                                             # it must
//                                                             # contain the
//                                                             # seconds
//                                                             # portion
//
// <Parsed Duration>    ::=  P<Date Duration>{<Time Duration>} # must contain
//                                                             # at least one
//                                                             # optional field
//                                                             # in <Date
//                                                             # Duration> or
//                                                             # must contain
//                                                             # a <Time
//                                                             # Duration>
//                                                             # (i.e. "P" is
//                                                             # not valid)
//..
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic 'bdlt::Iso8601Util' Usage
/// - - - - - - - - - - - - - - - - - - - - -
// This example demonstrates basic use of one 'generate' function and two
// 'parse' functions.
//
// First, we construct a few objects that are prerequisites for this and the
// following example:
//..
//  const bdlt::Date date(2005, 1, 31);     // 2005/01/31
//  const bdlt::Time time(8, 59, 59, 123);  // 08:59:59.123
//  const int        tzOffset = 240;        // +04:00 (four hours west of UTC)
//..
// Then, we construct a 'bdlt::DatetimeTz' object for which a corresponding ISO
// 8601-compliant string will be generated shortly:
//..
//  const bdlt::DatetimeTz sourceDatetimeTz(bdlt::Datetime(date, time),
//                                          tzOffset);
//..
// For comparison with the ISO 8601 string generated below, note that streaming
// the value of 'sourceDatetimeTz' to 'stdout':
//..
//  bsl::cout << sourceDatetimeTz << bsl::endl;
//..
// produces:
//..
//  31JAN2005_08:59:59.123000+0400
//..
// Next, we use a 'generate' function to produce an ISO 8601-compliant string
// for 'sourceDatetimeTz', writing the output to a 'bsl::ostringstream', and
// assert that both the return value and the string that is produced are as
// expected:
//..
//  bsl::ostringstream  oss;
//  const bsl::ostream& ret =
//                         bdlt::Iso8601Util::generate(oss, sourceDatetimeTz);
//  assert(&oss == &ret);
//
//  const bsl::string iso8601 = oss.str();
//  assert(iso8601 == "2005-01-31T08:59:59.123+04:00");
//..
// For comparison, see the output that was produced by the streaming operator
// above.
//
// Now, we parse the string that was just produced, loading the result of the
// parse into a second 'bdlt::DatetimeTz' object, and assert that the parse was
// successful and that the target object has the same value as that of the
// original (i.e., 'sourceDatetimeTz'):
//..
//  bdlt::DatetimeTz targetDatetimeTz;
//
//  int rc = bdlt::Iso8601Util::parse(&targetDatetimeTz,
//                                    iso8601.c_str(),
//                                    static_cast<int>(iso8601.length()));
//  assert(               0 == rc);
//  assert(sourceDatetimeTz == targetDatetimeTz);
//..
// Finally, we parse the 'iso8601' string a second time, this time loading the
// result into a 'bdlt::Datetime' object (instead of a 'bdlt::DatetimeTz'):
//..
//  bdlt::Datetime targetDatetime;
//
//  rc = bdlt::Iso8601Util::parse(&targetDatetime,
//                                iso8601.c_str(),
//                                static_cast<int>(iso8601.length()));
//  assert(                             0 == rc);
//  assert(sourceDatetimeTz.utcDatetime() == targetDatetime);
//..
// Note that this time the value of the target object has been converted to
// UTC.
//
///Example 2: Configuring ISO 8601 String Generation
///- - - - - - - - - - - - - - - - - - - - - - - - -
// This example demonstrates use of a 'bdlt::Iso8601UtilConfiguration' object
// to influence the format of the ISO 8601 strings that are generated by this
// component by passing that configuration object to 'generate'.  We also take
// this opportunity to illustrate the flavor of the 'generate' functions that
// outputs to a 'char *' buffer of a specified length.
//
// First, we construct a 'bdlt::TimeTz' object for which a corresponding ISO
// 8601-compliant string will be generated shortly:
//..
//  const bdlt::TimeTz sourceTimeTz(time, tzOffset);
//..
// For comparison with the ISO 8601 string generated below, note that streaming
// the value of 'sourceTimeTz' to 'stdout':
//..
//  bsl::cout << sourceTimeTz << bsl::endl;
//..
// produces:
//..
//  08:59:59.123+0400
//..
// Then, we construct the 'bdlt::Iso8601UtilConfiguration' object that
// indicates how we would like to affect the generated output ISO 8601 string.
// In this case, we want to use ',' as the decimal sign (in fractional seconds)
// and omit the ':' in zone designators:
//..
//  bdlt::Iso8601UtilConfiguration configuration;
//  configuration.setOmitColonInZoneDesignator(true);
//  configuration.setUseCommaForDecimalSign(true);
//..
// Next, we define the 'char *' buffer that will be used to stored the
// generated string.  A buffer of size 'bdlt::Iso8601Util::k_TIMETZ_STRLEN + 1'
// is large enough to hold any string generated by this component for a
// 'bdlt::TimeTz' object, including a null terminator:
//..
//  const int BUFLEN = bdlt::Iso8601Util::k_TIMETZ_STRLEN + 1;
//  char      buffer[BUFLEN];
//..
// Then, we use a 'generate' function that accepts our 'configuration' to
// produce an ISO 8601-compliant string for 'sourceTimeTz', this time writing
// the output to a 'char *' buffer, and assert that both the return value and
// the string that is produced are as expected.  Note that in comparing the
// return value against 'BUFLEN - 5' we account for the omission of the ':'
// from the zone designator, and also for the fact that, although a null
// terminator was generated, it is not included in the character count returned
// by 'generate'.  Also note that we use 'bsl::strcmp' to compare the resulting
// string knowing that we supplied a buffer having sufficient capacity to
// accommodate a null terminator:
//..
//  rc = bdlt::Iso8601Util::generate(buffer,
//                                   BUFLEN,
//                                   sourceTimeTz,
//                                   configuration);
//  assert(BUFLEN - 5 == rc);
//  assert(         0 == bsl::strcmp(buffer, "08:59:59,123+0400"));
//..
// For comparison, see the output that was produced by the streaming operator
// above.
//
// Next, we parse the string that was just produced, loading the result of the
// parse into a second 'bdlt::TimeTz' object, and assert that the parse was
// successful and that the target object has the same value as that of the
// original (i.e., 'sourceTimeTz').  Note that 'BUFLEN - 5' is passed and *not*
// 'BUFLEN' because the former indicates the correct number of characters in
// 'buffer' that we wish to parse:
//..
//  bdlt::TimeTz targetTimeTz;
//
//  rc = bdlt::Iso8601Util::parse(&targetTimeTz, buffer, BUFLEN - 5);
//
//  assert(           0 == rc);
//  assert(sourceTimeTz == targetTimeTz);
//..
// Then, we parse the string in 'buffer' a second time, this time loading the
// result into a 'bdlt::Time' object (instead of a 'bdlt::TimeTz'):
//..
//  bdlt::Time targetTime;
//
//  rc = bdlt::Iso8601Util::parse(&targetTime, buffer, BUFLEN - 5);
//  assert(                     0 == rc);
//  assert(sourceTimeTz.utcTime() == targetTime);
//..
// Note that this time the value of the target object has been converted to
// UTC.
//
// Finally, we modify the 'configuration' to display the 'bdlt::TimeTz' without
// fractional seconds:
//..
//  configuration.setFractionalSecondPrecision(0);
//  rc = bdlt::Iso8601Util::generate(buffer,
//                                   BUFLEN,
//                                   sourceTimeTz,
//                                   configuration);
//  assert(BUFLEN - 9 == rc);
//  assert(         0 == bsl::strcmp(buffer, "08:59:59+0400"));
//..

#include <bdlscm_version.h>

#include <bdlt_date.h>
#include <bdlt_datetime.h>
#include <bdlt_datetimetz.h>
#include <bdlt_datetz.h>
#include <bdlt_iso8601utilconfiguration.h>
#include <bdlt_time.h>
#include <bdlt_timetz.h>

#include <bdlb_variant.h>

#include <bslmf_assert.h>
#include <bslmf_issame.h>

#include <bsls_assert.h>
#include <bsls_libraryfeatures.h>

#include <bsl_ostream.h>
#include <bsl_string.h>

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
#include <memory_resource>  // 'std::pmr::polymorphic_allocator'
#endif  // BSLS_LIBRARYFEATURES_HAS_CPP17_PMR

#include <string>           // 'std::string', 'std::pmr::string'

namespace BloombergLP {
namespace bsls {

class TimeInterval;

}  // close namespace bsls

namespace bdlt {


                            // ==================
                            // struct Iso8601Util
                            // ==================

struct Iso8601Util {
    // This 'struct' provides a namespace for a suite of pure functions that
    // perform conversions between objects of 'bdlt' vocabulary type and their
    // ISO 8601 representations.  Each 'generate' and 'generateRaw' method
    // takes a 'bdlt' object (of type 'Date', 'DateTz', 'Time', 'TimeTz',
    // 'Datetime', or 'DatetimeTz') and outputs its corresponding ISO 8601
    // representation to a user-supplied character buffer or 'bsl::ostream'.
    // The 'parse' methods effect the opposite conversion in that they populate
    // a 'bdlt' object from the result of parsing an ISO 8601 representation.

  private:
    // PRIVATE CLASS METHOD
    static Iso8601UtilConfiguration defaultConfiguration();
        // Return a default configured configuration object.

  public:
    // TYPES
    enum {
        // This enumeration defines fixed lengths for the ISO 8601
        // representations of date, time, and datetime values.  Note that these
        // constants do *not* account for the null terminator that may be
        // produced by the 'generate' functions taking a 'bufferLength'
        // argument.

        k_DATE_STRLEN         = 10,  // 'bdlt::Date'
        k_DATETZ_STRLEN       = 16,  // 'bdlt::DateTz'

        k_TIME_STRLEN         = 15,  // 'bdlt::Time'
        k_TIMETZ_STRLEN       = 21,  // 'bdlt::TimeTz'

        k_DATETIME_STRLEN     = 26,  // 'bdlt::Datetime'
        k_DATETIMETZ_STRLEN   = 32,  // 'bdlt::DatetimeTz'

        k_TIMEINTERVAL_STRLEN = 38,  // 'bsls::TimeInterval'

        k_MAX_STRLEN          = k_TIMEINTERVAL_STRLEN

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
      , BDEPU_DATE_STRLEN         = k_DATE_STRLEN
      , BDEPU_DATETIME_STRLEN     = k_DATETIME_STRLEN
      , BDEPU_DATETIMETZ_STRLEN   = k_DATETIMETZ_STRLEN
      , BDEPU_DATETZ_STRLEN       = k_DATETZ_STRLEN
      , BDEPU_TIME_STRLEN         = k_TIME_STRLEN
      , BDEPU_TIMETZ_STRLEN       = k_TIMETZ_STRLEN
      , BDEPU_MAX_DATETIME_STRLEN = k_MAX_STRLEN

      , DATE_STRLEN               = k_DATE_STRLEN
      , DATETIME_STRLEN           = k_DATETIME_STRLEN
      , DATETIMETZ_STRLEN         = k_DATETIMETZ_STRLEN
      , DATETZ_STRLEN             = k_DATETZ_STRLEN
      , TIME_STRLEN               = k_TIME_STRLEN
      , TIMETZ_STRLEN             = k_TIMETZ_STRLEN
      , MAX_DATETIME_STRLEN       = k_MAX_STRLEN
#endif // BDE_OMIT_INTERNAL_DEPRECATED
    };

    typedef bdlb::Variant2<Date, DateTz>         DateOrDateTz;
        // 'DateOrDateTz' is a convenient alias for
        // 'bdlb::Variant2<Date, DateTz>'.

    typedef bdlb::Variant2<Time, TimeTz>         TimeOrTimeTz;
        // 'TimeOrTimeTz' is a convenient alias for
        // 'bdlb::Variant2<Time, TimeTz>'.

    typedef bdlb::Variant2<Datetime, DatetimeTz> DatetimeOrDatetimeTz;
        // 'DatetimeOrDatetimeTz' is a convenient alias for
        // 'bdlb::Variant2<Datetime, DatetimeTz>'.

    // CLASS METHODS
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const bsls::TimeInterval&        object);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const bsls::TimeInterval&        object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const Date&                      object);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const Date&                      object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const Time&                      object);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const Time&                      object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const Datetime&                  object);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const Datetime&                  object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const DateTz&                    object);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const DateTz&                    object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const TimeTz&                    object);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const TimeTz&                    object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const DatetimeTz&                object);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const DatetimeTz&                object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const DateOrDateTz&              object);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const DateOrDateTz&              object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const TimeOrTimeTz&              object);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const TimeOrTimeTz&              object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const DatetimeOrDatetimeTz&      object);
    static int generate(char                            *buffer,
                        int                              bufferLength,
                        const DatetimeOrDatetimeTz&      object,
                        const Iso8601UtilConfiguration&  configuration);
        // Write the ISO 8601 representation of the specified 'object' to the
        // specified 'buffer' of the specified 'bufferLength' (in bytes),
        // truncating (if necessary) to 'bufferLength'.  Optionally specify a
        // 'configuration' to affect the format of the generated string.  If
        // 'configuration' is not supplied, the process-wide default value
        // 'Iso8601UtilConfiguration::defaultConfiguration()' is used.  Return
        // the number of characters in the formatted string before truncation
        // (not counting a null terminator).  If 'bufferLength' indicates
        // sufficient capacity, 'buffer' is null terminated.  The behavior is
        // undefined unless '0 <= bufferLength'.  Note that a buffer of size
        // 'k_MAX_STRLEN + 1' is large enough to hold any string generated by
        // this component (counting a null terminator, if any).

    static int generate(bsl::string                     *string,
                        const bsls::TimeInterval&        object);
    static int generate(bsl::string                     *string,
                        const bsls::TimeInterval&        object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(bsl::string                     *string,
                        const Date&                      object);
    static int generate(bsl::string                     *string,
                        const Date&                      object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(bsl::string                     *string,
                        const Time&                      object);
    static int generate(bsl::string                     *string,
                        const Time&                      object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(bsl::string                     *string,
                        const Datetime&                  object);
    static int generate(bsl::string                     *string,
                        const Datetime&                  object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(bsl::string                     *string,
                        const DateTz&                    object);
    static int generate(bsl::string                     *string,
                        const DateTz&                    object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(bsl::string                     *string,
                        const TimeTz&                    object);
    static int generate(bsl::string                     *string,
                        const TimeTz&                    object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(bsl::string                     *string,
                        const DatetimeTz&                object);
    static int generate(bsl::string                     *string,
                        const DatetimeTz&                object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(bsl::string                     *string,
                        const DateOrDateTz&              object);
    static int generate(bsl::string                     *string,
                        const DateOrDateTz&              object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(bsl::string                     *string,
                        const TimeOrTimeTz&              object);
    static int generate(bsl::string                     *string,
                        const TimeOrTimeTz&              object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(bsl::string                     *string,
                        const DatetimeOrDatetimeTz&      object);
    static int generate(bsl::string                     *string,
                        const DatetimeOrDatetimeTz&      object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::string                     *string,
                        const bsls::TimeInterval&        object);
    static int generate(std::string                     *string,
                        const bsls::TimeInterval&        object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::string                     *string,
                        const Date&                      object);
    static int generate(std::string                     *string,
                        const Date&                      object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::string                     *string,
                        const Time&                      object);
    static int generate(std::string                     *string,
                        const Time&                      object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::string                     *string,
                        const Datetime&                  object);
    static int generate(std::string                     *string,
                        const Datetime&                  object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::string                     *string,
                        const DateTz&                    object);
    static int generate(std::string                     *string,
                        const DateTz&                    object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::string                     *string,
                        const TimeTz&                    object);
    static int generate(std::string                     *string,
                        const TimeTz&                    object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::string                     *string,
                        const DatetimeTz&                object);
    static int generate(std::string                     *string,
                        const DatetimeTz&                object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::string                     *string,
                        const DateOrDateTz&              object);
    static int generate(std::string                     *string,
                        const DateOrDateTz&              object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::string                     *string,
                        const TimeOrTimeTz&              object);
    static int generate(std::string                     *string,
                        const TimeOrTimeTz&              object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::string                     *string,
                        const DatetimeOrDatetimeTz&      object);
    static int generate(std::string                     *string,
                        const DatetimeOrDatetimeTz&      object,
                        const Iso8601UtilConfiguration&  configuration);

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
    static int generate(std::pmr::string                *string,
                        const bsls::TimeInterval&        object);
    static int generate(std::pmr::string                *string,
                        const bsls::TimeInterval&        object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::pmr::string                *string,
                        const Date&                      object);
    static int generate(std::pmr::string                *string,
                        const Date&                      object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::pmr::string                *string,
                        const Time&                      object);
    static int generate(std::pmr::string                *string,
                        const Time&                      object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::pmr::string                *string,
                        const Datetime&                  object);
    static int generate(std::pmr::string                *string,
                        const Datetime&                  object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::pmr::string                *string,
                        const DateTz&                    object);
    static int generate(std::pmr::string                *string,
                        const DateTz&                    object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::pmr::string                *string,
                        const TimeTz&                    object);
    static int generate(std::pmr::string                *string,
                        const TimeTz&                    object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::pmr::string                *string,
                        const DatetimeTz&                object);
    static int generate(std::pmr::string                *string,
                        const DatetimeTz&                object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::pmr::string                *string,
                        const DateOrDateTz&              object);
    static int generate(std::pmr::string                *string,
                        const DateOrDateTz&              object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::pmr::string                *string,
                        const TimeOrTimeTz&              object);
    static int generate(std::pmr::string                *string,
                        const TimeOrTimeTz&              object,
                        const Iso8601UtilConfiguration&  configuration);
    static int generate(std::pmr::string                *string,
                        const DatetimeOrDatetimeTz&      object);
    static int generate(std::pmr::string                *string,
                        const DatetimeOrDatetimeTz&      object,
                        const Iso8601UtilConfiguration&  configuration);
#endif
        // Load the ISO 8601 representation of the specified 'object' into the
        // specified 'string'.  Optionally specify a 'configuration' to affect
        // the format of the generated string.  If 'configuration' is not
        // supplied, the process-wide default value
        // 'Iso8601UtilConfiguration::defaultConfiguration()' is used.  Return
        // the number of characters in the formatted string.  The previous
        // contents of 'string' (if any) are discarded.

    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const bsls::TimeInterval&       object);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const bsls::TimeInterval&       object,
                                const Iso8601UtilConfiguration& configuration);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const Date&                     object);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const Date&                     object,
                                const Iso8601UtilConfiguration& configuration);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const Time&                     object);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const Time&                     object,
                                const Iso8601UtilConfiguration& configuration);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const Datetime&                 object);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const Datetime&                 object,
                                const Iso8601UtilConfiguration& configuration);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const DateTz&                   object);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const DateTz&                   object,
                                const Iso8601UtilConfiguration& configuration);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const TimeTz&                   object);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const TimeTz&                   object,
                                const Iso8601UtilConfiguration& configuration);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const DatetimeTz&               object);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const DatetimeTz&               object,
                                const Iso8601UtilConfiguration& configuration);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const DateOrDateTz&             object);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const DateOrDateTz&             object,
                                const Iso8601UtilConfiguration& configuration);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const TimeOrTimeTz&             object);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const TimeOrTimeTz&             object,
                                const Iso8601UtilConfiguration& configuration);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const DatetimeOrDatetimeTz&     object);
    static bsl::ostream& generate(
                                bsl::ostream&                   stream,
                                const DatetimeOrDatetimeTz&     object,
                                const Iso8601UtilConfiguration& configuration);
        // Write the ISO 8601 representation of the specified 'object' to the
        // specified 'stream'.  Optionally specify a 'configuration' to affect
        // the format of the generated string.  If 'configuration' is not
        // supplied, the process-wide default value
        // 'Iso8601UtilConfiguration::defaultConfiguration()' is used.  Return
        // a reference to 'stream'.  Note that 'stream' is not null terminated.

    static int generateRaw(char                            *buffer,
                           const bsls::TimeInterval&        object);
    static int generateRaw(char                            *buffer,
                           const bsls::TimeInterval&        object,
                           const Iso8601UtilConfiguration&  configuration);
    static int generateRaw(char                            *buffer,
                           const Date&                      object);
    static int generateRaw(char                            *buffer,
                           const Date&                      object,
                           const Iso8601UtilConfiguration&  configuration);
    static int generateRaw(char                            *buffer,
                           const Time&                      object);
    static int generateRaw(char                            *buffer,
                           const Time&                      object,
                           const Iso8601UtilConfiguration&  configuration);
    static int generateRaw(char                            *buffer,
                           const Datetime&                  object);
    static int generateRaw(char                            *buffer,
                           const Datetime&                  object,
                           const Iso8601UtilConfiguration&  configuration);
    static int generateRaw(char                            *buffer,
                           const DateTz&                    object);
    static int generateRaw(char                            *buffer,
                           const DateTz&                    object,
                           const Iso8601UtilConfiguration&  configuration);
    static int generateRaw(char                            *buffer,
                           const TimeTz&                    object);
    static int generateRaw(char                            *buffer,
                           const TimeTz&                    object,
                           const Iso8601UtilConfiguration&  configuration);
    static int generateRaw(char                            *buffer,
                           const DatetimeTz&                object);
    static int generateRaw(char                            *buffer,
                           const DatetimeTz&                object,
                           const Iso8601UtilConfiguration&  configuration);
    static int generateRaw(char                            *buffer,
                           const DateOrDateTz&              object);
    static int generateRaw(char                            *buffer,
                           const DateOrDateTz&              object,
                           const Iso8601UtilConfiguration&  configuration);
    static int generateRaw(char                            *buffer,
                           const TimeOrTimeTz&              object);
    static int generateRaw(char                            *buffer,
                           const TimeOrTimeTz&              object,
                           const Iso8601UtilConfiguration&  configuration);
    static int generateRaw(char                            *buffer,
                           const DatetimeOrDatetimeTz&      object);
    static int generateRaw(char                            *buffer,
                           const DatetimeOrDatetimeTz&      object,
                           const Iso8601UtilConfiguration&  configuration);
        // Write the ISO 8601 representation of the specified 'object' to the
        // specified 'buffer'.  Optionally specify a 'configuration' to affect
        // the format of the generated string.  If 'configuration' is not
        // supplied, the process-wide default value
        // 'Iso8601UtilConfiguration::defaultConfiguration()' is used.  Return
        // the number of characters in the formatted string.  'buffer' is not
        // null terminated.  The behavior is undefined unless 'buffer' has
        // sufficient capacity.  Note that a buffer of size 'k_MAX_STRLEN + 1'
        // is large enough to hold any string generated by this component
        // (counting a null terminator, if any).

    static int parse(bsls::TimeInterval *result,
                     const char         *string,
                     int                 length);
        // Parse the specified initial 'length' characters of the specified ISO
        // 8601 'string' as a 'bsls::TimeInterval' value, and load the value
        // into the specified 'result'.  Return 0 on success, and a non-zero
        // value (with no effect) otherwise.  'string' is assumed to be of the
        // form:
        //..
        //  <Parsed Duration>
        //..
        // See "Summary of Supported ISO 8601 Duration Representations" for a
        // complete description of this format.
        //
        // *Exactly* 'length' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'length' characters do not.  If an optional fractional second
        // having more than nine digits is present in 'string', it is rounded
        // to the nearest value in nanoseconds.  The behavior is undefined
        // unless '0 <= length'.

    static int parse(Date *result, const char *string, int length);
        // Parse the specified initial 'length' characters of the specified ISO
        // 8601 'string' as a 'Date' value, and load the value into the
        // specified 'result'.  Return 0 on success, and a non-zero value (with
        // no effect) otherwise.  'string' is assumed to be of the form:
        //..
        //  YYYY-MM-DD{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'length' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'length' characters do not.  If the optional zone designator
        // is present in 'string', it is parsed but ignored.  The behavior is
        // undefined unless '0 <= length'.

    static int parse(Time *result, const char *string, int length);
        // Parse the specified initial 'length' characters of the specified ISO
        // 8601 'string' as a 'Time' value, and load the value into the
        // specified 'result'.  Return 0 on success, and a non-zero value (with
        // no effect) otherwise.  'string' is assumed to be of the form:
        //..
        //  hh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'length' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'length' characters do not.  If an optional fractional second
        // having more than six digits is present in 'string', it is rounded to
        // the nearest value in microseconds.  If the optional zone designator
        // is present in 'string', the resulting 'Time' value is converted to
        // the equivalent UTC time; if the zone designator is absent, UTC is
        // assumed.  If a leap second is detected (i.e., the parsed value of
        // the 'second' attribute is 60; see {Leap Seconds}), the 'second'
        // attribute is taken to be 59, then an additional second is added to
        // 'result' at the end.  If the "hh:mm:ss" portion of 'string' is
        // "24:00:00", then the fractional second must be absent or 0, and the
        // zone designator must be absent or indicate UTC.  The behavior is
        // undefined unless '0 <= length'.

    static int parse(Datetime *result, const char *string, int length);
        // Parse the specified initial 'length' characters of the specified ISO
        // 8601 'string' as a 'Datetime' value, and load the value into the
        // specified 'result'.  Return 0 on success, and a non-zero value (with
        // no effect) otherwise.  'string' is assumed to be of the form:
        //..
        //  YYYY-MM-DDThh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'length' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'length' characters do not.  If an optional fractional second
        // having more than six digits is present in 'string', it is rounded to
        // the nearest value in microseconds.  If the optional zone designator
        // is present in 'string', the resulting 'Datetime' value is converted
        // to the equivalent UTC value; if the zone designator is absent, UTC
        // is assumed.  If a leap second is detected (i.e., the parsed value of
        // the 'second' attribute is 60; see {Leap Seconds}), the 'second'
        // attribute is taken to be 59, then an additional second is added to
        // 'result' at the end.  If the "hh:mm:ss" portion of 'string' is
        // "24:00:00", then the fractional second must be absent or 0, and the
        // zone designator must be absent or indicate UTC.  The behavior is
        // undefined unless '0 <= length'.

    static int parse(DateTz *result, const char *string, int length);
        // Parse the specified initial 'length' characters of the specified ISO
        // 8601 'string' as a 'DateTz' value, and load the value into the
        // specified 'result'.  Return 0 on success, and a non-zero value (with
        // no effect) otherwise.  'string' is assumed to be of the form:
        //..
        //  YYYY-MM-DD{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'length' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'length' characters do not.  If the optional zone designator
        // is not present in 'string', UTC is assumed.  The behavior is
        // undefined unless '0 <= length'.

    static int parse(TimeTz *result, const char *string, int length);
        // Parse the specified initial 'length' characters of the specified ISO
        // 8601 'string' as a 'TimeTz' value, and load the value into the
        // specified 'result'.  Return 0 on success, and a non-zero value (with
        // no effect) otherwise.  'string' is assumed to be of the form:
        //..
        //  hh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'length' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'length' characters do not.  If an optional fractional second
        // having more than six digits is present in 'string', it is rounded to
        // the nearest value in microseconds.  If the optional zone designator
        // is not present in 'string', UTC is assumed.  If a leap second is
        // detected (i.e., the parsed value of the 'second' attribute is 60;
        // see {Leap Seconds}), the 'second' attribute is taken to be 59, then
        // an additional second is added to 'result' at the end.  If the
        // "hh:mm:ss" portion of 'string' is "24:00:00", then the fractional
        // second must be absent or 0, and the zone designator must be absent
        // or indicate UTC.  The behavior is undefined unless '0 <= length'.

    static int parse(DatetimeTz *result, const char *string, int length);
        // Parse the specified initial 'length' characters of the specified ISO
        // 8601 'string' as a 'DatetimeTz' value, and load the value into the
        // specified 'result'.  Return 0 on success, and a non-zero value (with
        // no effect) otherwise.  'string' is assumed to be of the form:
        //..
        //  YYYY-MM-DDThh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'length' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'length' characters do not.  If an optional fractional second
        // having more than six digits is present in 'string', it is rounded to
        // the nearest value in microseconds.  If the optional zone designator
        // is not present in 'string', UTC is assumed.  If a leap second is
        // detected (i.e., the parsed value of the 'second' attribute is 60;
        // see {Leap Seconds}), the 'second' attribute is taken to be 59, then
        // an additional second is added to 'result' at the end.  If the
        // "hh:mm:ss" portion of 'string' is "24:00:00", then the fractional
        // second must be absent or 0, and the zone designator must be absent
        // or indicate UTC.  The behavior is undefined unless '0 <= length'.

    static int parse(DateOrDateTz *result, const char *string, int length);
        // Parse the specified initial 'length' characters of the specified ISO
        // 8601 'string' as a 'Date' or 'DateTz' value, depending on the
        // presence of a zone designator, and load the value into the specified
        // 'result'.  Return 0 on success, and a non-zero value (with no
        // effect) otherwise.  'string' is assumed to be of the form:
        //..
        //  YYYY-MM-DD{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'length' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'length' characters do not.  If the optional zone designator
        // is present in the 'string', the input is parsed as a 'DateTz' value,
        // and as a 'Date' value otherwise.  The behavior is undefined unless
        // '0 <= length'.

    static int parse(TimeOrTimeTz *result, const char *string, int length);
        // Parse the specified initial 'length' characters of the specified ISO
        // 8601 'string' as a 'Time' or 'TimeTz' value, depending on the
        // presence of a zone designator, and load the value into the specified
        // 'result'.  Return 0 on success, and a non-zero value (with no
        // effect) otherwise.  'string' is assumed to be of the form:
        //..
        //  hh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'length' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'length' characters do not.  If an optional fractional second
        // having more than six digits is present in 'string', it is rounded to
        // the nearest value in microseconds.  If the optional zone designator
        // is present in the 'string', the input is parsed as a 'TimeTz' value,
        // and as a 'Time' value otherwise.  If a leap second is detected
        // (i.e., the parsed value of the 'second' attribute is 60; see {Leap
        // Seconds}), the 'second' attribute is taken to be 59, then an
        // additional second is added to 'result' at the end.  If the
        // "hh:mm:ss" portion of 'string' is "24:00:00", then the fractional
        // second must be absent or 0, and the zone designator must be absent
        // or indicate UTC.  The behavior is undefined unless '0 <= length'.

    static int parse(DatetimeOrDatetimeTz *result,
                     const char           *string,
                     int                   length);
        // Parse the specified initial 'length' characters of the specified ISO
        // 8601 'string' as a 'Datetime' or  'DatetimeTz' value, depending on
        // the presence of a zone designator, and load the value into the
        // specified 'result'.  Return 0 on success, and a non-zero value (with
        // no effect) otherwise.  'string' is assumed to be of the form:
        //..
        //  YYYY-MM-DDThh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'length' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'length' characters do not.  If an optional fractional second
        // having more than six digits is present in 'string', it is rounded to
        // the nearest value in microseconds.  If the optional zone designator
        // is present in the 'string', the input is parsed as a 'DatetimeTz'
        // value, and as a 'Datetime' value otherwise.  If a leap second is
        // detected (i.e., the parsed value of the 'second' attribute is 60;
        // see {Leap Seconds}), the 'second' attribute is taken to be 59, then
        // an additional second is added to 'result' at the end.  If the
        // "hh:mm:ss" portion of 'string' is "24:00:00", then the fractional
        // second must be absent or 0, and the zone designator must be absent
        // or indicate UTC.  The behavior is undefined unless '0 <= length'.

    static int parse(bsls::TimeInterval      *result,
                     const bsl::string_view&  string);
        // Parse the specified ISO 8601 'string' as a 'bsls::TimeInterval'
        // value, and load the value into the specified 'result'.  Return 0 on
        // success, and a non-zero value (with no effect) otherwise.  'string'
        // is assumed to be of the form:
        //..
        //  <Parsed Duration>
        //..
        // See "Summary of Supported ISO 8601 Duration Representations" for a
        // complete description of this format.
        //
        // *Exactly* 'string.length()' characters are parsed; parsing will fail
        // if a proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If an optional
        // fractional second having more than nine digits is present in
        // 'string', it is rounded to the nearest value in nanoseconds.  The
        // behavior is undefined unless '0 <= length'.

    static int parse(Date *result, const bsl::string_view& string);
        // Parse the specified ISO 8601 'string' as a 'Date' value, and load
        // the value into the specified 'result'.  Return 0 on success, and a
        // non-zero value (with no effect) otherwise.  'string' is assumed to
        // be of the form:
        //..
        //  YYYY-MM-DD{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'string.length()' characters are parsed; parsing will fail
        // if a proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If the optional zone
        // designator is present in 'string', it is parsed but ignored.  The
        // behavior is undefined unless 'string.data()' is non-null.

    static int parse(Time *result, const bsl::string_view& string);
        // Parse the specified ISO 8601 'string' as a 'Time' value, and load
        // the value into the specified 'result'.  Return 0 on success, and a
        // non-zero value (with no effect) otherwise.  'string' is assumed to
        // be of the form:
        //..
        //  hh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'string.length()' characters are parsed; parsing will fail
        // if a proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If an optional
        // fractional second having more than six digits is present in
        // 'string', it is rounded to the nearest value in microseconds.  If
        // the optional zone designator is present in 'string', the resulting
        // 'Time' value is converted to the equivalent UTC time; if the zone
        // designator is absent, UTC is assumed.  If a leap second is detected
        // (i.e., the parsed value of the 'second' attribute is 60; see {Leap
        // Seconds}), the 'second' attribute is taken to be 59, then an
        // additional second is added to 'result' at the end.  If the
        // "hh:mm:ss" portion of 'string' is "24:00:00", then the fractional
        // second must be absent or 0, and the zone designator must be absent
        // or indicate UTC.  The behavior is undefined unless 'string.data()'
        // is non-null.

    static int parse(Datetime *result, const bsl::string_view& string);
        // Parse the specified ISO 8601 'string' as a 'Datetime' value, and
        // load the value into the specified 'result'.  Return 0 on success,
        // and a non-zero value (with no effect) otherwise.  'string' is
        // assumed to be of the form:
        //..
        //  YYYY-MM-DDThh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'string.length()' characters are parsed; parsing will fail
        // if a proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If an optional
        // fractional second having more than six digits is present in
        // 'string', it is rounded to the nearest value in microseconds.  If
        // the optional zone designator is present in 'string', the resulting
        // 'Datetime' value is converted to the equivalent UTC value; if the
        // zone designator is absent, UTC is assumed.  If a leap second is
        // detected (i.e., the parsed value of the 'second' attribute is 60;
        // see {Leap Seconds}), the 'second' attribute is taken to be 59, then
        // an additional second is added to 'result' at the end.  If the
        // "hh:mm:ss" portion of 'string' is "24:00:00", then the fractional
        // second must be absent or 0, and the zone designator must be absent
        // or indicate UTC.  The behavior is undefined unless 'string.data()'
        // is non-null.

    static int parse(DateTz *result, const bsl::string_view& string);
        // Parse the specified ISO 8601 'string' as a 'DateTz' value, and load
        // the value into the specified 'result'.  Return 0 on success, and a
        // non-zero value (with no effect) otherwise.  'string' is assumed to
        // be of the form:
        //..
        //  YYYY-MM-DD{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'string.length()' characters are parsed; parsing will fail
        // if a proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If the optional zone
        // designator is not present in 'string', UTC is assumed.  The behavior
        // is undefined unless 'string.data()' is non-null.

    static int parse(TimeTz *result, const bsl::string_view& string);
        // Parse the specified ISO 8601 'string' as a 'TimeTz' value, and load
        // the value into the specified 'result'.  Return 0 on success, and a
        // non-zero value (with no effect) otherwise.  'string' is assumed to
        // be of the form:
        //..
        //  hh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'string.length()' characters are parsed; parsing will fail
        // if a proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If an optional
        // fractional second having more than six digits is present in
        // 'string', it is rounded to the nearest value in microseconds.  If
        // the optional zone designator is not present in 'string', UTC is
        // assumed.  If a leap second is detected (i.e., the parsed value of
        // the 'second' attribute is 60; see {Leap Seconds}), the 'second'
        // attribute is taken to be 59, then an additional second is added to
        // 'result' at the end.  If the "hh:mm:ss" portion of 'string' is
        // "24:00:00", then the fractional second must be absent or 0, and the
        // zone designator must be absent or indicate UTC.  The behavior is
        // undefined unless 'string.data()' is non-null.

    static int parse(DatetimeTz *result, const bsl::string_view& string);
        // Parse the specified ISO 8601 'string' as a 'DatetimeTz' value, and
        // load the value into the specified 'result'.  Return 0 on success,
        // and a non-zero value (with no effect) otherwise.  'string' is
        // assumed to be of the form:
        //..
        //  YYYY-MM-DDThh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'string.length()' characters are parsed; parsing will fail
        // if a proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If an optional
        // fractional second having more than six digits is present in
        // 'string', it is rounded to the nearest value in microseconds.  If
        // the optional zone designator is not present in 'string', UTC is
        // assumed.  If a leap second is detected (i.e., the parsed value of
        // the 'second' attribute is 60; see {Leap Seconds}), the 'second'
        // attribute is taken to be 59, then an additional second is added to
        // 'result' at the end.  If the "hh:mm:ss" portion of 'string' is
        // "24:00:00", then the fractional second must be absent or 0, and the
        // zone designator must be absent or indicate UTC.  The behavior is
        // undefined unless 'string.data()' is non-null.

    static int parse(DateOrDateTz *result, const bsl::string_view& string);
        // Parse the specified ISO 8601 'string' as a 'Date' or 'DateTz' value,
        // depending on the presence of a zone designator, and load the value
        // into the specified 'result'.  Return 0 on success, and a non-zero
        // value (with no effect) otherwise.  'string' is assumed to be of the
        // form:
        //..
        //  YYYY-MM-DD{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'string.length()' characters are parsed; parsing will fail
        // if a proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If the optional zone
        // designator is present in the 'string', the input is parsed as a
        // 'DateTz' value, and as a 'Date' value otherwise.  The behavior is
        // undefined unless 'string.data()' is non-null.

    static int parse(TimeOrTimeTz *result, const bsl::string_view& string);
        // Parse the specified ISO 8601 'string' as a 'Time' or 'TimeTz' value,
        // depending on the presence of a zone designator, and load the value
        // into the specified 'result'.  Return 0 on success, and a non-zero
        // value (with no effect) otherwise.  'string' is assumed to be of the
        // form:
        //..
        //  hh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'string.length()' characters are parsed; parsing will fail
        // if a proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If an optional
        // fractional second having more than six digits is present in
        // 'string', it is rounded to the nearest value in microseconds.  If
        // the optional zone designator is present in the 'string', the input
        // is parsed as a 'TimeTz' value, and as a 'Time' value otherwise.  If
        // a leap second is detected (i.e., the parsed value of the 'second'
        // attribute is 60; see {Leap Seconds}), the 'second' attribute is
        // taken to be 59, then an additional second is added to 'result' at
        // the end.  If the "hh:mm:ss" portion of 'string' is "24:00:00", then
        // the fractional second must be absent or 0, and the zone designator
        // must be absent or indicate UTC.  The behavior is undefined unless
        // 'string.data()' is non-null.

    static int parse(DatetimeOrDatetimeTz    *result,
                     const bsl::string_view&  string);
        // Parse the specified ISO 8601 'string' as a 'Datetime' or
        // 'DatetimeTz' value, depending on the presence of a zone designator,
        // and load the value into the specified 'result'.  Return 0 on
        // success, and a non-zero value (with no effect) otherwise.  'string'
        // is assumed to be of the form:
        //..
        //  YYYY-MM-DDThh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // *Exactly* 'string.length()' characters are parsed; parsing will fail
        // if a proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If an optional
        // fractional second having more than six digits is present in
        // 'string', it is rounded to the nearest value in microseconds.  If
        // the optional zone designator is present in the 'string', the input
        // is parsed as a 'DatetimeTz' value, and as a 'Datetime' value
        // otherwise.  If a leap second is detected (i.e., the parsed value of
        // the 'second' attribute is 60; see {Leap Seconds}), the 'second'
        // attribute is taken to be 59, then an additional second is added to
        // 'result' at the end.  If the "hh:mm:ss" portion of 'string' is
        // "24:00:00", then the fractional second must be absent or 0, and the
        // zone designator must be absent or indicate UTC.  The behavior is
        // undefined unless 'string.data()' is non-null.

    static int parseRelaxed(Datetime *result, const char *string, int length);
        // Parse the specified initial 'length' characters of the specified
        // "relaxed" ISO 8601 'string' as a 'Datetime' value, and load the
        // value into the specified 'result'.  Return 0 on success, and a
        // non-zero value (with no effect) otherwise.  'string' is assumed to
        // be of the form:
        //..
        //  YYYY-MM-DD(T| )hh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // The "relaxed" format parsed by this function is a superset of the
        // strict ISO 8601 format, currently allowing a SPACE character to be
        // used as a separated (where ISO 8601 requires a 'T').  *Exactly*
        // 'length' characters are parsed; parsing will fail if a proper prefix
        // of 'string' matches the expected format, but the entire 'length'
        // characters do not.  If an optional fractional second having more
        // than six digits is present in 'string', it is rounded to the nearest
        // value in microseconds.  If the optional zone designator is present
        // in 'string', the resulting 'Datetime' value is converted to the
        // equivalent UTC value; if the zone designator is absent, UTC is
        // assumed.  If a leap second is detected (i.e., the parsed value of
        // the 'second' attribute is 60; see {Leap Seconds}), the 'second'
        // attribute is taken to be 59, then an additional second is added to
        // 'result' at the end.  If the "hh:mm:ss" portion of 'string' is
        // "24:00:00", then the fractional second must be absent or 0, and the
        // zone designator must be absent or indicate UTC.  The behavior is
        // undefined unless '0 <= length'.

    static int parseRelaxed(DatetimeTz *result,
                            const char *string,
                            int         length);
        // Parse the specified initial 'length' characters of the specified
        // "relaxed" ISO 8601 'string' as a 'DatetimeTz' value, and load the
        // value into the specified 'result'.  Return 0 on success, and a
        // non-zero value (with no effect) otherwise.  'string' is assumed to
        // be of the form:
        //..
        //  YYYY-MM-DD(T| )hh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // The "relaxed" format parsed by this function is a superset of the
        // strict ISO 8601 format, currently allowing a SPACE character to be
        // used as a separated (where ISO 8601 requires a 'T').  *Exactly*
        // 'length' characters are parsed; parsing will fail if a proper prefix
        // of 'string' matches the expected format, but the entire 'length'
        // characters do not.  If an optional fractional second having more
        // than six digits is present in 'string', it is rounded to the nearest
        // value in microseconds.  If the optional zone designator is not
        // present in 'string', UTC is assumed.  If a leap second is detected
        // (i.e., the parsed value of the 'second' attribute is 60; see {Leap
        // Seconds}), the 'second' attribute is taken to be 59, then an
        // additional second is added to 'result' at the end.  If the
        // "hh:mm:ss" portion of 'string' is "24:00:00", then the fractional
        // second must be absent or 0, and the zone designator must be absent
        // or indicate UTC.  The behavior is undefined unless '0 <= length'.

    static int parseRelaxed(DatetimeOrDatetimeTz *result,
                            const char           *string,
                            int                   length);
        // Parse the specified initial 'length' characters of the specified
        // "relaxed" ISO 8601 'string' as a 'Datetime' or 'DatetimeTz' value,
        // depending on the presence of a zone designator, and load the value
        // into the specified 'result'.  Return 0 on success, and a non-zero
        // value (with no effect) otherwise.  'string' is assumed to be of the
        // form:
        //..
        //  YYYY-MM-DD(T| )hh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // The "relaxed" format parsed by this function is a superset of the
        // strict ISO 8601 format, currently allowing a SPACE character to be
        // used as a separated (where ISO 8601 requires a 'T').  *Exactly*
        // 'length' characters are parsed;    parsing will fail if a proper
        // prefix of 'string' matches the expected format, but the entire
        // 'length' characters do not.  If an optional fractional second having
        // more than six digits is present in 'string', it is rounded to the
        // nearest value in microseconds.  If the optional zone designator is
        // present in the 'string', the input is parsed as a 'DatetimeTz'
        // value, and as a 'Datetime' value otherwise.  If a leap second is
        // detected (i.e., the parsed value of the 'second' attribute is 60;
        // see {Leap Seconds}), the 'second' attribute is taken to be 59, then
        // an additional second is added to 'result' at the end.  If the
        // "hh:mm:ss" portion of 'string' is "24:00:00", then the fractional
        // second must be absent or 0, and the zone designator must be absent
        // or indicate UTC.  The behavior is undefined unless '0 <= length'.

    static int parseRelaxed(Datetime *result, const bsl::string_view& string);
        // Parse the specified "relaxed" ISO 8601 'string' as a 'Datetime'
        // value, and load the value into the specified 'result'.  Return 0 on
        // success, and a non-zero value (with no effect) otherwise.  'string'
        // is assumed to be of the form:
        //..
        //  YYYY-MM-DD(T| )hh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // The "relaxed" format parsed by this function is a superset of the
        // strict ISO 8601 format, currently allowing a SPACE character to be
        // used as a separated (where ISO 8601 requires a 'T').  *Exactly*
        // 'string.length()' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If an optional
        // fractional second having more than six digits is present in
        // 'string', it is rounded to the nearest value in microseconds.  If
        // the optional zone designator is present in 'string', the resulting
        // 'Datetime' value is converted to the equivalent UTC value; if the
        // zone designator is absent, UTC is assumed.  If a leap second is
        // detected (i.e., the parsed value of the 'second' attribute is 60;
        // see {Leap Seconds}), the 'second' attribute is taken to be 59, then
        // an additional second is added to 'result' at the end.  If the
        // "hh:mm:ss" portion of 'string' is "24:00:00", then the fractional
        // second must be absent or 0, and the zone designator must be absent
        // or indicate UTC.  The behavior is undefined unless 'string.data()'
        // is non-null.

    static int parseRelaxed(DatetimeTz              *result,
                            const bsl::string_view&  string);
        // Parse the specified "relaxed" ISO 8601 'string' as a 'DatetimeTz'
        // value, and load the value into the specified 'result'.  Return 0 on
        // success, and a non-zero value (with no effect) otherwise.  'string'
        // is assumed to be of the form:
        //..
        //  YYYY-MM-DD(T| )hh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // The "relaxed" format parsed by this function is a superset of the
        // strict ISO 8601 format, currently allowing a SPACE character to be
        // used as a separated (where ISO 8601 requires a 'T').  *Exactly*
        // 'string.length()' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If an optional
        // fractional second having more than six digits is present in
        // 'string', it is rounded to the nearest value in microseconds.  If
        // the optional zone designator is not present in 'string', UTC is
        // assumed.  If a leap second is detected (i.e., the parsed value of
        // the 'second' attribute is 60; see {Leap Seconds}), the 'second'
        // attribute is taken to be 59, then an additional second is added to
        // 'result' at the end.  If the "hh:mm:ss" portion of 'string' is
        // "24:00:00", then the fractional second must be absent or 0, and the
        // zone designator must be absent or indicate UTC.  The behavior is
        // undefined unless 'string.data()' is non-null.

    static int parseRelaxed(DatetimeOrDatetimeTz    *result,
                            const bsl::string_view&  string);
        // Parse the specified "relaxed" ISO 8601 'string' as a 'Datetime' or
        // 'DatetimeTz' value, depending on the presence of a zone designator,
        // and load the value into the specified 'result'.  Return 0 on
        // success, and a non-zero value (with no effect) otherwise.  'string'
        // is assumed to be of the form:
        //..
        //  YYYY-MM-DD(T| )hh:mm:ss{(.|,)s+}{(+|-)hh{:}mm|Z}
        //..
        // The "relaxed" format parsed by this function is a superset of the
        // strict ISO 8601 format, currently allowing a SPACE character to be
        // used as a separated (where ISO 8601 requires a 'T').  *Exactly*
        // 'string.length()' characters are parsed; parsing will fail if a
        // proper prefix of 'string' matches the expected format, but the
        // entire 'string.length()' characters do not.  If an optional
        // fractional second having more than six digits is present in
        // 'string', it is rounded to the nearest value in microseconds.  If
        // the optional zone designator is present in the 'string', the input
        // is parsed as a 'DatetimeTz' value, and as a 'Datetime' value
        // otherwise.  If a leap second is detected (i.e., the parsed value of
        // the 'second' attribute is 60; see {Leap Seconds}), the 'second'
        // attribute is taken to be 59, then an additional second is added to
        // 'result' at the end.  If the "hh:mm:ss" portion of 'string' is
        // "24:00:00", then the fractional second must be absent or 0, and the
        // zone designator must be absent or indicate UTC.  The behavior is
        // undefined unless 'string.data()' is non-null.

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
    static int generate(char              *buffer,
                        const Date&        object,
                        int                bufferLength);
    static int generate(char              *buffer,
                        const Time&        object,
                        int                bufferLength);
    static int generate(char              *buffer,
                        const Datetime&    object,
                        int                bufferLength);
    static int generate(char              *buffer,
                        const DateTz&      object,
                        int                bufferLength);
    static int generate(char              *buffer,
                        const TimeTz&      object,
                        int                bufferLength);
    static int generate(char              *buffer,
                        const DatetimeTz&  object,
                        int                bufferLength);
        // !DEPRECATED!: Use the overloads taking the 'bufferLength' argument
        // *before* the 'object' argument instead.

    static int generate(char              *buffer,
                        const DateTz&      object,
                        int                bufferLength,
                        bool               useZAbbreviationForUtc);
    static int generate(char              *buffer,
                        const TimeTz&      object,
                        int                bufferLength,
                        bool               useZAbbreviationForUtc);
    static int generate(char              *buffer,
                        const DatetimeTz&  object,
                        int                bufferLength,
                        bool               useZAbbreviationForUtc);
        // !DEPRECATED!: Use the overloads taking an 'Iso8601UtilConfiguration'
        // object instead.

    static bsl::ostream& generate(bsl::ostream&     stream,
                                  const DateTz&     object,
                                  bool              useZAbbreviationForUtc);
    static bsl::ostream& generate(bsl::ostream&     stream,
                                  const TimeTz&     object,
                                  bool              useZAbbreviationForUtc);
    static bsl::ostream& generate(bsl::ostream&     stream,
                                  const DatetimeTz& object,
                                  bool              useZAbbreviationForUtc);
        // !DEPRECATED!: Use the overloads taking an 'Iso8601UtilConfiguration'
        // object instead.

    static int generateRaw(char              *buffer,
                           const DateTz&      object,
                           bool               useZAbbreviationForUtc);
    static int generateRaw(char              *buffer,
                           const TimeTz&      object,
                           bool               useZAbbreviationForUtc);
    static int generateRaw(char              *buffer,
                           const DatetimeTz&  object,
                           bool               useZAbbreviationForUtc);
        // !DEPRECATED!: Use the overloads taking an 'Iso8601UtilConfiguration'
        // object instead.

#endif  // BDE_OMIT_INTERNAL_DEPRECATED
};

// ============================================================================
//                             INLINE DEFINITIONS
// ============================================================================

                            // ------------------
                            // struct Iso8601Util
                            // ------------------

// PRIVATE CLASS METHODS
inline
Iso8601UtilConfiguration Iso8601Util::defaultConfiguration()
{
    return Iso8601UtilConfiguration::defaultConfiguration();
}

// CLASS METHODS
inline
int Iso8601Util::generate(char                     *buffer,
                          int                       bufferLength,
                          const bsls::TimeInterval& object)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= bufferLength);

    return generate(buffer,
                    bufferLength,
                    object,
                    defaultConfiguration());
}

inline
int Iso8601Util::generate(char *buffer, int bufferLength, const Date& object)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= bufferLength);

    return generate(buffer,
                    bufferLength,
                    object,
                    defaultConfiguration());
}

inline
int Iso8601Util::generate(char *buffer, int bufferLength, const Time& object)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= bufferLength);

    return generate(buffer,
                    bufferLength,
                    object,
                    defaultConfiguration());
}

inline
int
Iso8601Util::generate(char *buffer, int bufferLength, const Datetime& object)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= bufferLength);

    return generate(buffer,
                    bufferLength,
                    object,
                    defaultConfiguration());
}

inline
int Iso8601Util::generate(char *buffer, int bufferLength, const DateTz& object)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= bufferLength);

    return generate(buffer,
                    bufferLength,
                    object,
                    defaultConfiguration());
}

inline
int Iso8601Util::generate(char *buffer, int bufferLength, const TimeTz& object)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= bufferLength);

    return generate(buffer,
                    bufferLength,
                    object,
                    defaultConfiguration());
}

inline
int
Iso8601Util::generate(char *buffer, int bufferLength, const DatetimeTz& object)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= bufferLength);

    return generate(buffer,
                    bufferLength,
                    object,
                    defaultConfiguration());
}

inline
int Iso8601Util::generate(char                *buffer,
                          int                  bufferLength,
                          const DateOrDateTz&  object)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= bufferLength);

    return generate(buffer,
                    bufferLength,
                    object,
                    defaultConfiguration());
}

inline
int Iso8601Util::generate(char                *buffer,
                          int                  bufferLength,
                          const TimeOrTimeTz&  object)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= bufferLength);

    return generate(buffer,
                    bufferLength,
                    object,
                    defaultConfiguration());
}

inline
int Iso8601Util::generate(char                        *buffer,
                          int                          bufferLength,
                          const DatetimeOrDatetimeTz&  object)
{
    BSLS_ASSERT_SAFE(buffer);
    BSLS_ASSERT_SAFE(0 <= bufferLength);

    return generate(buffer,
                    bufferLength,
                    object,
                    defaultConfiguration());
}

inline
int Iso8601Util::generate(bsl::string              *string,
                          const bsls::TimeInterval& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(bsl::string *string, const Date& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(bsl::string *string, const Time& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(bsl::string *string, const Datetime& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(bsl::string *string, const DateTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(bsl::string *string, const TimeTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(bsl::string *string, const DatetimeTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(bsl::string *string, const DateOrDateTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(bsl::string *string, const TimeOrTimeTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(bsl::string                 *string,
                          const DatetimeOrDatetimeTz&  object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::string              *string,
                          const bsls::TimeInterval& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::string *string, const Date& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::string *string, const Time& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::string *string, const Datetime& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::string *string, const DateTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::string *string, const TimeTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::string *string, const DatetimeTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::string *string, const DateOrDateTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::string *string, const TimeOrTimeTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::string                 *string,
                          const DatetimeOrDatetimeTz&  object)
{
    return generate(string, object, defaultConfiguration());
}

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
inline
int Iso8601Util::generate(std::pmr::string         *string,
                          const bsls::TimeInterval& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::pmr::string *string, const Date& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::pmr::string *string, const Time& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::pmr::string *string, const Datetime& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::pmr::string *string, const DateTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::pmr::string *string, const TimeTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::pmr::string *string, const DatetimeTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::pmr::string *string, const DateOrDateTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::pmr::string *string, const TimeOrTimeTz& object)
{
    return generate(string, object, defaultConfiguration());
}

inline
int Iso8601Util::generate(std::pmr::string            *string,
                          const DatetimeOrDatetimeTz&  object)
{
    return generate(string, object, defaultConfiguration());
}
#endif

inline
bsl::ostream& Iso8601Util::generate(bsl::ostream&             stream,
                                    const bsls::TimeInterval& object)
{
    return generate(stream,
                    object,
                    defaultConfiguration());
}

inline
bsl::ostream& Iso8601Util::generate(
                                 bsl::ostream&                   stream,
                                 const bsls::TimeInterval&       object,
                                 const Iso8601UtilConfiguration& configuration)
{
    char buffer[k_TIMEINTERVAL_STRLEN + 1];

    const int len = generate(buffer,
                             k_TIMEINTERVAL_STRLEN,
                             object,
                             configuration);
    BSLS_ASSERT_SAFE(k_TIMEINTERVAL_STRLEN >= len);

    return stream.write(buffer, len);
}

inline
bsl::ostream& Iso8601Util::generate(bsl::ostream& stream, const Date& object)
{
    return generate(stream,
                    object,
                    defaultConfiguration());
}

inline
bsl::ostream& Iso8601Util::generate(
                                 bsl::ostream&                   stream,
                                 const Date&                     object,
                                 const Iso8601UtilConfiguration& configuration)
{
    char buffer[k_DATE_STRLEN + 1];

    const int len = generate(buffer, k_DATE_STRLEN, object, configuration);
    BSLS_ASSERT_SAFE(k_DATE_STRLEN >= len);

    return stream.write(buffer, len);
}

inline
bsl::ostream& Iso8601Util::generate(bsl::ostream& stream, const Time& object)
{
    return generate(stream,
                    object,
                    defaultConfiguration());
}

inline
bsl::ostream& Iso8601Util::generate(
                                 bsl::ostream&                   stream,
                                 const Time&                     object,
                                 const Iso8601UtilConfiguration& configuration)
{
    char buffer[k_TIME_STRLEN + 1];

    const int len = generate(buffer, k_TIME_STRLEN, object, configuration);
    BSLS_ASSERT_SAFE(k_TIME_STRLEN >= len);

    return stream.write(buffer, len);
}

inline
bsl::ostream&
Iso8601Util::generate(bsl::ostream& stream, const Datetime& object)
{
    return generate(stream,
                    object,
                    defaultConfiguration());
}

inline
bsl::ostream& Iso8601Util::generate(
                                 bsl::ostream&                   stream,
                                 const Datetime&                 object,
                                 const Iso8601UtilConfiguration& configuration)
{
    char buffer[k_DATETIME_STRLEN + 1];

    const int len = generate(buffer, k_DATETIME_STRLEN, object, configuration);
    BSLS_ASSERT_SAFE(k_DATETIME_STRLEN >= len);

    return stream.write(buffer, len);
}

inline
bsl::ostream& Iso8601Util::generate(bsl::ostream& stream, const DateTz& object)
{
    return generate(stream,
                    object,
                    defaultConfiguration());
}

inline
bsl::ostream& Iso8601Util::generate(
                                 bsl::ostream&                   stream,
                                 const DateTz&                   object,
                                 const Iso8601UtilConfiguration& configuration)
{
    char buffer[k_DATETZ_STRLEN + 1];

    const int len = generate(buffer, k_DATETZ_STRLEN, object, configuration);
    BSLS_ASSERT_SAFE(k_DATETZ_STRLEN >= len);

    return stream.write(buffer, len);
}

inline
bsl::ostream& Iso8601Util::generate(bsl::ostream& stream, const TimeTz& object)
{
    return generate(stream,
                    object,
                    defaultConfiguration());
}

inline
bsl::ostream& Iso8601Util::generate(
                                 bsl::ostream&                   stream,
                                 const TimeTz&                   object,
                                 const Iso8601UtilConfiguration& configuration)
{
    char buffer[k_TIMETZ_STRLEN + 1];

    const int len = generate(buffer, k_TIMETZ_STRLEN, object, configuration);
    BSLS_ASSERT_SAFE(k_TIMETZ_STRLEN >= len);

    return stream.write(buffer, len);
}

inline
bsl::ostream&
Iso8601Util::generate(bsl::ostream& stream, const DatetimeTz& object)
{
    return generate(stream,
                    object,
                    defaultConfiguration());
}

inline
bsl::ostream& Iso8601Util::generate(
                                 bsl::ostream&                   stream,
                                 const DatetimeTz&               object,
                                 const Iso8601UtilConfiguration& configuration)
{
    char buffer[k_DATETIMETZ_STRLEN + 1];

    const int len = generate(buffer,
                             k_DATETIMETZ_STRLEN,
                             object,
                             configuration);
    BSLS_ASSERT_SAFE(k_DATETIMETZ_STRLEN >= len);

    return stream.write(buffer, len);
}

inline
bsl::ostream&
Iso8601Util::generate(bsl::ostream& stream, const DateOrDateTz& object)
{
    return generate(stream,
                    object,
                    defaultConfiguration());
}

inline
bsl::ostream& Iso8601Util::generate(
                                 bsl::ostream&                   stream,
                                 const DateOrDateTz&             object,
                                 const Iso8601UtilConfiguration& configuration)
{
    char buffer[k_DATETZ_STRLEN + 1];

    const int len = generate(buffer,
                             k_DATETZ_STRLEN,
                             object,
                             configuration);
    BSLS_ASSERT_SAFE(k_DATETZ_STRLEN >= len);

    return stream.write(buffer, len);
}

inline
bsl::ostream&
Iso8601Util::generate(bsl::ostream& stream, const TimeOrTimeTz& object)
{
    return generate(stream,
                    object,
                    defaultConfiguration());
}

inline
bsl::ostream& Iso8601Util::generate(
                                 bsl::ostream&                   stream,
                                 const TimeOrTimeTz&             object,
                                 const Iso8601UtilConfiguration& configuration)
{
    char buffer[k_TIMETZ_STRLEN + 1];

    const int len = generate(buffer,
                             k_TIMETZ_STRLEN,
                             object,
                             configuration);
    BSLS_ASSERT_SAFE(k_TIMETZ_STRLEN >= len);

    return stream.write(buffer, len);
}

inline
bsl::ostream&
Iso8601Util::generate(bsl::ostream& stream, const DatetimeOrDatetimeTz& object)
{
    return generate(stream,
                    object,
                    defaultConfiguration());
}

inline
bsl::ostream& Iso8601Util::generate(
                                 bsl::ostream&                   stream,
                                 const DatetimeOrDatetimeTz&     object,
                                 const Iso8601UtilConfiguration& configuration)
{
    char buffer[k_DATETIMETZ_STRLEN + 1];

    const int len = generate(buffer,
                             k_DATETIMETZ_STRLEN,
                             object,
                             configuration);
    BSLS_ASSERT_SAFE(k_DATETIMETZ_STRLEN >= len);

    return stream.write(buffer, len);
}

inline
int Iso8601Util::generateRaw(char *buffer, const bsls::TimeInterval& object)
{
    BSLS_ASSERT_SAFE(buffer);

    return generateRaw(buffer,
                       object,
                       defaultConfiguration());
}

inline
int Iso8601Util::generateRaw(char *buffer, const Date& object)
{
    BSLS_ASSERT_SAFE(buffer);

    return generateRaw(buffer,
                       object,
                       defaultConfiguration());
}

inline
int Iso8601Util::generateRaw(char *buffer, const Time& object)
{
    BSLS_ASSERT_SAFE(buffer);

    return generateRaw(buffer,
                       object,
                       defaultConfiguration());
}

inline
int Iso8601Util::generateRaw(char *buffer, const Datetime& object)
{
    BSLS_ASSERT_SAFE(buffer);

    return generateRaw(buffer,
                       object,
                       defaultConfiguration());
}

inline
int Iso8601Util::generateRaw(char *buffer, const DateTz& object)
{
    BSLS_ASSERT_SAFE(buffer);

    return generateRaw(buffer,
                       object,
                       defaultConfiguration());
}

inline
int Iso8601Util::generateRaw(char *buffer, const TimeTz& object)
{
    BSLS_ASSERT_SAFE(buffer);

    return generateRaw(buffer,
                       object,
                       defaultConfiguration());
}

inline
int Iso8601Util::generateRaw(char *buffer, const DatetimeTz& object)
{
    BSLS_ASSERT_SAFE(buffer);

    return generateRaw(buffer,
                       object,
                       defaultConfiguration());
}

inline
int Iso8601Util::generateRaw(char *buffer, const DateOrDateTz& object)
{
    BSLS_ASSERT_SAFE(buffer);

    return generateRaw(buffer,
                       object,
                       defaultConfiguration());
}

inline
int Iso8601Util::generateRaw(char *buffer, const TimeOrTimeTz& object)
{
    BSLS_ASSERT_SAFE(buffer);

    return generateRaw(buffer,
                       object,
                       defaultConfiguration());
}

inline
int Iso8601Util::generateRaw(char *buffer, const DatetimeOrDatetimeTz& object)
{
    BSLS_ASSERT_SAFE(buffer);

    return generateRaw(buffer,
                       object,
                       defaultConfiguration());
}

inline
int Iso8601Util::parse(bsls::TimeInterval      *result,
                       const bsl::string_view&  string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parse(result, string.data(), static_cast<int>(string.length()));
}

inline
int Iso8601Util::parse(Date *result, const bsl::string_view& string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parse(result, string.data(), static_cast<int>(string.length()));
}

inline
int Iso8601Util::parse(Time *result, const bsl::string_view& string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parse(result, string.data(), static_cast<int>(string.length()));
}

inline
int Iso8601Util::parse(Datetime *result, const bsl::string_view& string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parse(result, string.data(), static_cast<int>(string.length()));
}

inline
int Iso8601Util::parse(DateTz *result, const bsl::string_view& string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parse(result, string.data(), static_cast<int>(string.length()));
}

inline
int Iso8601Util::parse(TimeTz *result, const bsl::string_view& string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parse(result, string.data(), static_cast<int>(string.length()));
}

inline
int Iso8601Util::parse(DatetimeTz *result, const bsl::string_view& string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parse(result, string.data(), static_cast<int>(string.length()));
}

inline
int Iso8601Util::parse(DateOrDateTz *result, const bsl::string_view& string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parse(result, string.data(), static_cast<int>(string.length()));
}

inline
int Iso8601Util::parse(TimeOrTimeTz *result, const bsl::string_view& string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parse(result, string.data(), static_cast<int>(string.length()));
}

inline
int Iso8601Util::parse(DatetimeOrDatetimeTz    *result,
                       const bsl::string_view&  string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parse(result, string.data(), static_cast<int>(string.length()));
}

inline
int Iso8601Util::parseRelaxed(Datetime *result, const bsl::string_view& string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parseRelaxed(result,
                        string.data(),
                        static_cast<int>(string.length()));
}

inline
int Iso8601Util::parseRelaxed(DatetimeTz              *result,
                              const bsl::string_view&  string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parseRelaxed(result,
                        string.data(),
                        static_cast<int>(string.length()));
}

inline
int Iso8601Util::parseRelaxed(DatetimeOrDatetimeTz    *result,
                              const bsl::string_view&  string)
{
    BSLS_ASSERT_SAFE(string.data());

    return parseRelaxed(result,
                        string.data(),
                        static_cast<int>(string.length()));
}

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
inline
int Iso8601Util::generate(char *buffer, const Date& object, int bufferLength)
{
    return generate(buffer, bufferLength, object);
}

inline
int Iso8601Util::generate(char *buffer, const Time& object, int bufferLength)
{
    return generate(buffer, bufferLength, object);
}

inline
int Iso8601Util::generate(char            *buffer,
                          const Datetime&  object,
                          int              bufferLength)
{
    return generate(buffer, bufferLength, object);
}

inline
int Iso8601Util::generate(char *buffer, const DateTz& object, int bufferLength)
{
    return generate(buffer, bufferLength, object);
}

inline
int Iso8601Util::generate(char *buffer, const TimeTz& object, int bufferLength)
{
    return generate(buffer, bufferLength, object);
}

inline
int Iso8601Util::generate(char              *buffer,
                          const DatetimeTz&  object,
                          int                bufferLength)
{
    return generate(buffer, bufferLength, object);
}

inline
int Iso8601Util::generate(char          *buffer,
                          const DateTz&  object,
                          int            bufferLength,
                          bool           useZAbbreviationForUtc)
{
    Iso8601UtilConfiguration configuration = defaultConfiguration();
    configuration.setUseZAbbreviationForUtc(useZAbbreviationForUtc);

    return generate(buffer, bufferLength, object, configuration);
}

inline
int Iso8601Util::generate(char          *buffer,
                          const TimeTz&  object,
                          int            bufferLength,
                          bool           useZAbbreviationForUtc)
{
    Iso8601UtilConfiguration configuration = defaultConfiguration();
    configuration.setUseZAbbreviationForUtc(useZAbbreviationForUtc);

    return generate(buffer, bufferLength, object, configuration);
}

inline
int Iso8601Util::generate(char              *buffer,
                          const DatetimeTz&  object,
                          int                bufferLength,
                          bool               useZAbbreviationForUtc)
{
    Iso8601UtilConfiguration configuration = defaultConfiguration();
    configuration.setUseZAbbreviationForUtc(useZAbbreviationForUtc);

    return generate(buffer, bufferLength, object, configuration);
}

inline
bsl::ostream& Iso8601Util::generate(bsl::ostream& stream,
                                    const DateTz& object,
                                    bool          useZAbbreviationForUtc)
{
    Iso8601UtilConfiguration configuration = defaultConfiguration();
    configuration.setUseZAbbreviationForUtc(useZAbbreviationForUtc);

    return generate(stream, object, configuration);
}

inline
bsl::ostream& Iso8601Util::generate(bsl::ostream& stream,
                                    const TimeTz& object,
                                    bool          useZAbbreviationForUtc)
{
    Iso8601UtilConfiguration configuration = defaultConfiguration();
    configuration.setUseZAbbreviationForUtc(useZAbbreviationForUtc);

    return generate(stream, object, configuration);
}

inline
bsl::ostream& Iso8601Util::generate(bsl::ostream&     stream,
                                    const DatetimeTz& object,
                                    bool              useZAbbreviationForUtc)
{
    Iso8601UtilConfiguration configuration = defaultConfiguration();
    configuration.setUseZAbbreviationForUtc(useZAbbreviationForUtc);

    return generate(stream, object, configuration);
}

inline
int Iso8601Util::generateRaw(char          *buffer,
                             const DateTz&  object,
                             bool           useZAbbreviationForUtc)
{
    Iso8601UtilConfiguration configuration = defaultConfiguration();
    configuration.setUseZAbbreviationForUtc(useZAbbreviationForUtc);

    return generateRaw(buffer, object, configuration);
}

inline
int Iso8601Util::generateRaw(char          *buffer,
                             const TimeTz&  object,
                             bool           useZAbbreviationForUtc)
{
    Iso8601UtilConfiguration configuration = defaultConfiguration();
    configuration.setUseZAbbreviationForUtc(useZAbbreviationForUtc);

    return generateRaw(buffer, object, configuration);
}

inline
int Iso8601Util::generateRaw(char              *buffer,
                             const DatetimeTz&  object,
                             bool               useZAbbreviationForUtc)
{
    Iso8601UtilConfiguration configuration = defaultConfiguration();
    configuration.setUseZAbbreviationForUtc(useZAbbreviationForUtc);

    return generateRaw(buffer, object, configuration);
}
#endif  // BDE_OMIT_INTERNAL_DEPRECATED

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2016 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------