// bdlt_fixutil.h                                                     -*-C++-*-

#ifndef INCLUDED_BDLT_FIXUTIL
#define INCLUDED_BDLT_FIXUTIL

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

//@PURPOSE: Provide conversions between date/time objects and FIX strings.
//
//@CLASSES:
//  bdlt::FixUtil: namespace for FIX date/time conversion functions
//
//@SEE_ALSO: bdlt_fixutilconfiguration
//
//@DESCRIPTION: This component provides a namespace, `bdlt::FixUtil`,
// containing functions that convert `bdlt` date, time, and datetime objects to
// and from ("generate" and "parse", respectively) corresponding string
// representations that are compliant with the FIX standard.  The version of
// the FIX standard that is the basis for this component can be found at:
// ```
// http://www.fixtradingcommunity.org/FIXimate/FIXimate3.0/latestEP/en/
//                                         FIX.5.0SP2_EP208/fix_datatypes.html
// ```
// In general terms, `FixUtil` functions support what FIX refers to as
// *complete* *representations* in *extended* *format*.  We first present a
// brief overview before delving into the details of the FIX representations
// that are supported for each of the relevant `bdlt` vocabulary types.
//
// Each function that *generates* FIX strings (named `generate` and
// `generateRaw`) takes a `bdlt` object and a `char *` buffer, `bsl::string`,
// or `bsl::ostream`, and writes a FIX representation of the object to the
// buffer, string, or stream.  The "raw" functions are distinguished from their
// non-"raw" counterparts in three respects:
//
// * The length of the `char *` buffer is not supplied to the `generateRaw`
//   functions.
// * The `generateRaw` functions do not output a null terminator.
// * 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::FixUtilConfiguration`
// object, which is discussed shortly.)
//
// Each function that *parses* FIX strings (named `parse`) take the address of
// a target `bdlt` 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 FIX, some terms from that specification are used
// liberally in what follows.  Two FIX terms of particular note are *timezone*
// *offset* and *fractional* *second*.
//
// A FIX *timezone* *offset* 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 FIX string `20020317-15:46:00+04:00`
// has a timezone offset of `+04:00`, indicating a timezone 4 hours ahead of
// UTC.
//
// A FIX *fractional* *second* corresponds to, for example, combined
// `millisecond` and `microsecond` attributes of a `bdlt::Datetime` or
// `bdlt::Time` object.  For example, the `Time` value (and FIX string)
// `15:46:09.330` has a `millisecond` attribute value of 330; i.e., a
// fractional second of .33.
//
///FIX String Generation
///---------------------
// Strings produced by the `generate` and `generateRaw` functions are a
// straightforward transposition of the attributes of the source `bdlt` value
// into an appropriate FIX format, and are best illustrated by a few examples.
// Note that for `Datetime`, `DatetimeTz`, and `Time`, the fractional second is
// generated with the precision specified in the configuration.  Also note that
// for `TimeTz`, no fractional second is generated (as per the FIX
// specification for "TZTimeOnly").
// ```
// +--------------------------------------+---------------------------------+
// |             Object Value             |      Generated FIX String       |
// |                                      |  (using default configuration)  |
// +======================================+=================================+
// |  Date(2002, 03, 17)                  |  20020317                       |
// +--------------------------------------+---------------------------------+
// |  Time(15, 46, 09, 330)               |  15:46:09.330                   |
// +--------------------------------------+---------------------------------+
// |  Datetime(Date(2002, 03, 17)         |                                 |
// |           Time(15, 46, 09, 330))     |  20020317-15:46:09.330          |
// +--------------------------------------+---------------------------------+
// |  DateTz(Date(2002, 03, 17), -120)    |  20020317-02:00                 |
// +--------------------------------------+---------------------------------+
// |  TimeTz(Time(15, 46, 09, 330), 270)  |  15:46:09+04:30                 |
// +--------------------------------------+---------------------------------+
// |  DatetimeTz(Datetime(                |                                 |
// |              Date(2002, 03, 17),     |                                 |
// |              Time(15, 46, 09, 330)), |                                 |
// |             0)                       |  20020317-15:46:09.330+00:00    |
// +--------------------------------------+---------------------------------+
// ```
// Note that the FIX 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 `FixUtilConfiguration`, enables
// configuration of two aspects of FIX string generation:
//
// * The precision of the fractional seconds.
// * Whether `Z` is output for the timezone offset instead of `+00:00` (UTC).
//
// `FixUtilConfiguration` has two 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_fixutilconfiguration` for details.
//
///FIX 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 `FixUtilConfiguration` argument).  Moreover, the process-wide
// configuration has no effect on parsing either.  Instead, the parse methods
// automatically treat `+00:00` and `Z` as equivalent timezone offsets (both
// denoting UTC).  Finally, the parsing allows seconds to be optionally
// specified in all types, which is in contradiction to some of the types in
// the referenced FIX protocol specification.
//
///Timezone Offsets
/// - - - - - - - -
// The timezone offset is optional, and can be present when parsing for *any*
// type, i.e., even for `Date`, `Time`, and `Datetime`.  If a timezone offset
// 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 timezone offset present in the parsed string will affect the
// resulting object value (unless the timezone offset denotes UTC) because the
// result is converted to UTC.  If the timezone offset is absent, it is treated
// as if `+00:00` were specified:
// ```
// +------------------------------------+-----------------------------------+
// |         Parsed FIX String          |        Result Object Value        |
// +====================================+===================================+
// |  20020317-02:00                    |  Date(2002, 03, 17)               |
// |                                    |  # timezone offset ignored        |
// +------------------------------------+-----------------------------------+
// |  20020317-02:65                    |  Date: parsing fails              |
// |                                    |  # invalid timezone offset        |
// +------------------------------------+-----------------------------------+
// |  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'               |
// +------------------------------------+-----------------------------------+
// |  20020317-23: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 (in divergence with the referenced
// FIX protocol document, which indicates the fractional second may be
// unspecified or have a positive multiple of three digits).  Although FIX has
// provision for picosecond (or finer) time resolution, be aware that `bdlt` is
// limited to microsecond resolution.  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.  These
// roundings may incur a carry of one second into the `second` attribute:
// ```
// +--------------------------------------+---------------------------------+
// |          Parsed FIX String           |      Result Object Value        |
// +======================================+=================================+
// |  15:46:09.1                          |  Time(15, 46, 09, 100)          |
// +--------------------------------------+---------------------------------+
// |  15:46:09-05:00                      |  TimeTz(Time(15, 46, 09), -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)          |
// |                                      |  # round up and carry           |
// +--------------------------------------+---------------------------------+
// ```
// Note that, for `Datetime` and `DatetimeTz`, if a carry due to rounding of
// the fractional second causes an overflow at the extreme upper end of the
// valid range of dates (i.e., 9999/12/31), then parsing fails.
//
///Leap Seconds
/// - - - - - -
// Leap seconds are not representable by `bdlt::Time` or `bdlt::Datetime`.
// Hence, they are not produced by any of the `FixUtil` 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`, and `millisecond` attributes.  Note that this behavior is more
// generous than that afforded by the FIX 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 a FIX 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
/// - - - - - - -
// Although 24:00 is *representable* by `bdlt`, i.e., as the default value for
// `bdlt::Time`, "24:00:00.000" is *not* a valid string in the FIX protocol.
// As per other methods acting upon 24:00 within `bdlt`, an `hour` attribute
// value of 24 is mapped to 0 by the generate functions provided by this
// component:
// ```
// +------------------------------------+-----------------------------------+
// |        Source Object Value         |       Generated FIX String        |
// +====================================+===================================+
// |  Time(24, 0, 0, 0)                 |  00:00:00.000                     |
// +------------------------------------+-----------------------------------+
// |  Datetime(Date(2002, 03, 17),      |  20020317-00:00:00.000            |
// |           Time(24, 0, 0, 0))       |                                   |
// +------------------------------------+-----------------------------------+
// ```
// Finally, a string representing 24:00 is rejected by the `bdlt::FixUtil`
// parse methods.
//
///Summary of Supported FIX Representations
///- - - - - - - - - - - - - - - - - - - -
// The syntax description below summarizes the FIX string representations
// supported by this component.  Although not quoted (for readability),
// `[+-:.Z]` are literal characters that can occur in FIX strings.  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 FIXED><ZONE>
//
// <Parsed TimeTz>         ::=  <TIME FLEXIBLE>{<ZONE>}
//
// <Generated Datetime>    ::=  <DATE>-<TIME FLEXIBLE>
//
// <Parsed Datetime>       ::=  <Parsed DatetimeTz>
//
// <Generated DatetimeTz>  ::=  <DATE>-<TIME FLEXIBLE><ZONE>
//
// <Parsed DatetimeTz>     ::=  <DATE>-<TIME FLEXIBLE>{<ZONE>}
//
// <DATE>                  ::=  YYYYMMDD
//
// <TIME FIXED>            ::=  hh:mm:ss
//
// <TIME FLEXIBLE>         ::=  hh:mm{:ss{.s+}}
//
// <ZONE>                  ::=  ((+|-)hh{:mm})|Z  # timezone offset, the colon
//                                                # and minute attribute are
//                                                # optional during parsing
// ```
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic `bdlt::FixUtil` 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
// FIX-compliant string will be generated shortly:
// ```
// const bdlt::DatetimeTz sourceDatetimeTz(bdlt::Datetime(date, time),
//                                         tzOffset);
// ```
// For comparison with the FIX 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 a FIX-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::FixUtil::generate(oss, sourceDatetimeTz);
// assert(&oss == &ret);
//
// const bsl::string fix = oss.str();
// assert(fix == "20050131-08: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::FixUtil::parse(&targetDatetimeTz,
//                               fix.c_str(),
//                               static_cast<int>(fix.length()));
// assert(               0 == rc);
// assert(sourceDatetimeTz == targetDatetimeTz);
// ```
// Finally, we parse the `fix` string a second time, this time loading the
// result into a `bdlt::Datetime` object (instead of a `bdlt::DatetimeTz`):
// ```
// bdlt::Datetime targetDatetime;
//
// rc = bdlt::FixUtil::parse(&targetDatetime,
//                           fix.c_str(),
//                           static_cast<int>(fix.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 FIX String Generation
///- - - - - - - - - - - - - - - - - - - - - -
// This example demonstrates use of a `bdlt::FixUtilConfiguration` object to
// influence the format of the FIX 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 the `bdlt::FixUtilConfiguration` object that indicates
// how we would like to affect the generated output FIX string.  In this case,
// we want to have microsecond precision displayed:
// ```
// bdlt::FixUtilConfiguration configuration;
//
// configuration.setFractionalSecondPrecision(6);
// ```
// Then, we define the `char *` buffer that will be used to stored the
// generated string.  A buffer of size `bdlt::FixUtil::k_DATETIMETZ_STRLEN + 1`
// is large enough to hold any string generated by this component for a
// `bdlt::DatetimeTz` object, including a null terminator:
// ```
// const int BUFLEN = bdlt::FixUtil::k_DATETIMETZ_STRLEN + 1;
// char      buffer[BUFLEN];
// ```
// Next, we use a `generate` function that accepts our `configuration` to
// produce a FIX-compliant string for `sourceDatetimeTz`, 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 - 1` we account 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::FixUtil::generate(buffer,
//                              BUFLEN,
//                              sourceDatetimeTz,
//                              configuration);
// assert(BUFLEN - 1 == rc);
// assert(         0 == bsl::strcmp(buffer,
//                                  "20050131-08:59:59.123000+04:00"));
// ```
// 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::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`).  Note that `BUFLEN - 1` is passed and
// *not* `BUFLEN` because the former indicates the correct number of characters
// in `buffer` that we wish to parse:
// ```
// rc = bdlt::FixUtil::parse(&targetDatetimeTz, buffer, BUFLEN - 1);
//
// assert(               0 == rc);
// assert(sourceDatetimeTz == targetDatetimeTz);
// ```
// Then, we parse the string in `buffer` a second time, this time loading the
// result into a `bdlt::Datetime` object (instead of a `bdlt::DatetimeTz`):
// ```
// rc = bdlt::FixUtil::parse(&targetDatetime, buffer, BUFLEN - 1);
//
// assert(                             0 == rc);
// assert(sourceDatetimeTz.utcDatetime() == targetDatetime);
// ```
// Note that this time the value of the target object has been converted to
// UTC.
//
// Finally, we modify the `configuration` to display the `bdlt::DatetimeTz`
// without fractional seconds:
// ```
// configuration.setFractionalSecondPrecision(0);
// rc = bdlt::FixUtil::generate(buffer,
//                              BUFLEN,
//                              sourceDatetimeTz,
//                              configuration);
// assert(BUFLEN - 8 == rc);
// assert(         0 == bsl::strcmp(buffer, "20050131-08:59:59+04:00"));
// ```

#include <bdlscm_version.h>

#include <bdlt_fixutilconfiguration.h>

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

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

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

namespace BloombergLP {
namespace bdlt {

class Date;
class DateTz;
class Datetime;
class DatetimeTz;
class Time;
class TimeTz;

class  FixUtilConfiguration;

                              // ==============
                              // struct FixUtil
                              // ==============

/// This `struct` provides a namespace for a suite of pure functions that
/// perform conversions between objects of `bdlt` vocabulary type and their
/// FIX representations.  Each `generate` and `generateRaw` method takes a
/// `bdlt` object (of type `Date`, `DateTz`, `Time`, `TimeTz`, `Datetime`,
/// or `DatetimeTz`) and outputs its corresponding FIX 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 a FIX representation.
struct FixUtil {

    // TYPES

    /// This enumeration defines fixed lengths for the FIX 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.
    enum {
        k_DATE_STRLEN       =  8,  // `bdlt::Date`
        k_DATETZ_STRLEN     = 14,  // `bdlt::DateTz`

        k_TIME_STRLEN       = 15,  // `bdlt::Time`
        k_TIMETZ_STRLEN     = 14,  // `bdlt::TimeTz`

        k_DATETIME_STRLEN   = 24,  // `bdlt::Datetime`
        k_DATETIMETZ_STRLEN = 30,  // `bdlt::DatetimeTz`

        k_MAX_STRLEN        = k_DATETIMETZ_STRLEN
    };

    // CLASS METHODS

    /// Write the FIX 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
    /// `FixUtilConfiguration::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(char                        *buffer,
                        int                          bufferLength,
                        const Date&                  object);
    static int generate(char                        *buffer,
                        int                          bufferLength,
                        const Date&                  object,
                        const FixUtilConfiguration&  configuration);
    static int generate(char                        *buffer,
                        int                          bufferLength,
                        const Time&                  object);
    static int generate(char                        *buffer,
                        int                          bufferLength,
                        const Time&                  object,
                        const FixUtilConfiguration&  configuration);
    static int generate(char                        *buffer,
                        int                          bufferLength,
                        const Datetime&              object);
    static int generate(char                        *buffer,
                        int                          bufferLength,
                        const Datetime&              object,
                        const FixUtilConfiguration&  configuration);
    static int generate(char                        *buffer,
                        int                          bufferLength,
                        const DateTz&                object);
    static int generate(char                        *buffer,
                        int                          bufferLength,
                        const DateTz&                object,
                        const FixUtilConfiguration&  configuration);
    static int generate(char                        *buffer,
                        int                          bufferLength,
                        const TimeTz&                object);
    static int generate(char                        *buffer,
                        int                          bufferLength,
                        const TimeTz&                object,
                        const FixUtilConfiguration&  configuration);
    static int generate(char                        *buffer,
                        int                          bufferLength,
                        const DatetimeTz&            object);
    static int generate(char                        *buffer,
                        int                          bufferLength,
                        const DatetimeTz&            object,
                        const FixUtilConfiguration&  configuration);

    static int generate(bsl::string                 *string,
                        const Date&                  object);
    static int generate(bsl::string                 *string,
                        const Date&                  object,
                        const FixUtilConfiguration&  configuration);
    static int generate(bsl::string                 *string,
                        const Time&                  object);
    static int generate(bsl::string                 *string,
                        const Time&                  object,
                        const FixUtilConfiguration&  configuration);
    static int generate(bsl::string                 *string,
                        const Datetime&              object);
    static int generate(bsl::string                 *string,
                        const Datetime&              object,
                        const FixUtilConfiguration&  configuration);
    static int generate(bsl::string                 *string,
                        const DateTz&                object);
    static int generate(bsl::string                 *string,
                        const DateTz&                object,
                        const FixUtilConfiguration&  configuration);
    static int generate(bsl::string                 *string,
                        const TimeTz&                object);
    static int generate(bsl::string                 *string,
                        const TimeTz&                object,
                        const FixUtilConfiguration&  configuration);
    static int generate(bsl::string                 *string,
                        const DatetimeTz&            object);
    static int generate(bsl::string                 *string,
                        const DatetimeTz&            object,
                        const FixUtilConfiguration&  configuration);

    static int generate(std::string                 *string,
                        const Date&                  object);
    static int generate(std::string                 *string,
                        const Date&                  object,
                        const FixUtilConfiguration&  configuration);
    static int generate(std::string                 *string,
                        const Time&                  object);
    static int generate(std::string                 *string,
                        const Time&                  object,
                        const FixUtilConfiguration&  configuration);
    static int generate(std::string                 *string,
                        const Datetime&              object);
    static int generate(std::string                 *string,
                        const Datetime&              object,
                        const FixUtilConfiguration&  configuration);
    static int generate(std::string                 *string,
                        const DateTz&                object);
    static int generate(std::string                 *string,
                        const DateTz&                object,
                        const FixUtilConfiguration&  configuration);
    static int generate(std::string                 *string,
                        const TimeTz&                object);
    static int generate(std::string                 *string,
                        const TimeTz&                object,
                        const FixUtilConfiguration&  configuration);
    static int generate(std::string                 *string,
                        const DatetimeTz&            object);
    static int generate(std::string                 *string,
                        const DatetimeTz&            object,
                        const FixUtilConfiguration&  configuration);

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR_STRING
    /// Load the FIX 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
    /// `FixUtilConfiguration::defaultConfiguration()` is used.  Return the
    /// number of characters in the formatted string.  The previous contents
    /// of `string` (if any) are discarded.
    static int generate(std::pmr::string            *string,
                        const Date&                  object);
    static int generate(std::pmr::string            *string,
                        const Date&                  object,
                        const FixUtilConfiguration&  configuration);
    static int generate(std::pmr::string            *string,
                        const Time&                  object);
    static int generate(std::pmr::string            *string,
                        const Time&                  object,
                        const FixUtilConfiguration&  configuration);
    static int generate(std::pmr::string            *string,
                        const Datetime&              object);
    static int generate(std::pmr::string            *string,
                        const Datetime&              object,
                        const FixUtilConfiguration&  configuration);
    static int generate(std::pmr::string            *string,
                        const DateTz&                object);
    static int generate(std::pmr::string            *string,
                        const DateTz&                object,
                        const FixUtilConfiguration&  configuration);
    static int generate(std::pmr::string            *string,
                        const TimeTz&                object);
    static int generate(std::pmr::string            *string,
                        const TimeTz&                object,
                        const FixUtilConfiguration&  configuration);
    static int generate(std::pmr::string            *string,
                        const DatetimeTz&            object);
    static int generate(std::pmr::string            *string,
                        const DatetimeTz&            object,
                        const FixUtilConfiguration&  configuration);
#endif

    /// Write the FIX 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
    /// `FixUtilConfiguration::defaultConfiguration()` is used.  Return a
    /// reference to `stream`.  Note that `stream` is not null terminated.
    static bsl::ostream& generate(bsl::ostream&               stream,
                                  const Date&                 object);
    static bsl::ostream& generate(bsl::ostream&               stream,
                                  const Date&                 object,
                                  const FixUtilConfiguration& configuration);
    static bsl::ostream& generate(bsl::ostream&               stream,
                                  const Time&                 object);
    static bsl::ostream& generate(bsl::ostream&               stream,
                                  const Time&                 object,
                                  const FixUtilConfiguration& configuration);
    static bsl::ostream& generate(bsl::ostream&               stream,
                                  const Datetime&             object);
    static bsl::ostream& generate(bsl::ostream&               stream,
                                  const Datetime&             object,
                                  const FixUtilConfiguration& configuration);
    static bsl::ostream& generate(bsl::ostream&               stream,
                                  const DateTz&               object);
    static bsl::ostream& generate(bsl::ostream&               stream,
                                  const DateTz&               object,
                                  const FixUtilConfiguration& configuration);
    static bsl::ostream& generate(bsl::ostream&               stream,
                                  const TimeTz&               object);
    static bsl::ostream& generate(bsl::ostream&               stream,
                                  const TimeTz&               object,
                                  const FixUtilConfiguration& configuration);
    static bsl::ostream& generate(bsl::ostream&               stream,
                                  const DatetimeTz&           object);
    static bsl::ostream& generate(bsl::ostream&               stream,
                                  const DatetimeTz&           object,
                                  const FixUtilConfiguration& configuration);

    /// Write the FIX 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
    /// `FixUtilConfiguration::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 generateRaw(char                        *buffer,
                           const Date&                  object);
    static int generateRaw(char                        *buffer,
                           const Date&                  object,
                           const FixUtilConfiguration&  configuration);
    static int generateRaw(char                        *buffer,
                           const Time&                  object);
    static int generateRaw(char                        *buffer,
                           const Time&                  object,
                           const FixUtilConfiguration&  configuration);
    static int generateRaw(char                        *buffer,
                           const Datetime&              object);
    static int generateRaw(char                        *buffer,
                           const Datetime&              object,
                           const FixUtilConfiguration&  configuration);
    static int generateRaw(char                        *buffer,
                           const DateTz&                object);
    static int generateRaw(char                        *buffer,
                           const DateTz&                object,
                           const FixUtilConfiguration&  configuration);
    static int generateRaw(char                        *buffer,
                           const TimeTz&                object);
    static int generateRaw(char                        *buffer,
                           const TimeTz&                object,
                           const FixUtilConfiguration&  configuration);
    static int generateRaw(char                        *buffer,
                           const DatetimeTz&            object);
    static int generateRaw(char                        *buffer,
                           const DatetimeTz&            object,
                           const FixUtilConfiguration&  configuration);

    /// Parse the specified initial `length` characters of the specified FIX
    /// `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:
    /// ```
    /// YYYYMMDD{(+|-)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 timezone offset
    /// is present in `string`, it is parsed but ignored.  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 FIX
    /// `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 timezone
    /// offset is present in `string`, the resulting `Time` value is
    /// converted to the equivalent UTC time; if the timezone offset 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.  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 FIX
    /// `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:
    /// ```
    /// YYYYMMDD-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 timezone offset
    /// is present in `string`, the resulting `Datetime` value is converted
    /// to the equivalent UTC value; if the timezone offset 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.  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 FIX
    /// `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:
    /// ```
    /// YYYYMMDD{(+|-)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 timezone offset
    /// is not present in `string`, UTC is assumed.  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 FIX
    /// `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 timezone
    /// offset 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.  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 FIX
    /// `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:
    /// ```
    /// YYYYMMDD-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 timezone offset
    /// 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.  The behavior
    /// is undefined unless `0 <= length`.
    static int parse(DatetimeTz *result, const char *string, int length);

    /// Parse the specified FIX `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:
    /// ```
    /// YYYYMMDD{(+|-)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
    /// timezone offset is present in `string`, it is parsed but ignored.
    /// The behavior is undefined unless `string.data()` is non-null.
    static int parse(Date *result, const bsl::string_view& string);

    /// Parse the specified FIX `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 timezone offset is present in `string`, the resulting
    /// `Time` value is converted to the equivalent UTC time; if the
    /// timezone offset 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.  The behavior
    /// is undefined unless `string.data()` is non-null.
    static int parse(Time *result, const bsl::string_view& string);

    /// Parse the specified FIX `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:
    /// ```
    /// YYYYMMDD-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 timezone offset is present in `string`, the resulting
    /// `Datetime` value is converted to the equivalent UTC value; if the
    /// timezone offset 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.  The behavior
    /// is undefined unless `string.data()` is non-null.
    static int parse(Datetime *result, const bsl::string_view& string);

    /// Parse the specified FIX `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:
    /// ```
    /// YYYYMMDD{(+|-)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
    /// timezone offset is not present in `string`, UTC is assumed.  The
    /// behavior is undefined unless `string.data()` is non-null.
    static int parse(DateTz *result, const bsl::string_view& string);

    /// Parse the specified FIX `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 timezone offset 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.  The behavior is undefined unless
    /// `string.data()` is non-null.
    static int parse(TimeTz *result, const bsl::string_view& string);

    /// Parse the specified FIX `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:
    /// ```
    /// YYYYMMDD-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 timezone offset 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.  The behavior is undefined unless
    /// `string.data()` is non-null.
    static int parse(DatetimeTz *result, const bsl::string_view& string);
};

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

                              // --------------
                              // struct FixUtil
                              // --------------

// CLASS METHODS
inline
int FixUtil::generate(char *buffer, int bufferLength, const Date& object)
{
    BSLS_ASSERT(buffer);
    BSLS_ASSERT(0 <= bufferLength);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR_STRING
inline
int FixUtil::generate(std::pmr::string *string, const Date& object)
{
    return generate(string,
                    object,
                    FixUtilConfiguration::defaultConfiguration());
}

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

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

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

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

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

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

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

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

    return stream.write(buffer, len);
}

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

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

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

    return stream.write(buffer, len);
}

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

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

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

    return stream.write(buffer, len);
}

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

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

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

    return stream.write(buffer, len);
}

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

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

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

    return stream.write(buffer, len);
}

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

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

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

    return stream.write(buffer, len);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#endif

// ----------------------------------------------------------------------------
// Copyright 2017 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 ----------------------------------
