// bdlt_datetimeinterval.h -*-C++-*- #ifndef INCLUDED_BDLT_DATETIMEINTERVAL #define INCLUDED_BDLT_DATETIMEINTERVAL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a representation of an interval of time. // //@CLASSES: // bdlt::DatetimeInterval: time interval with microsecond resolution // //@SEE_ALSO: // //@DESCRIPTION: This component implements a time interval class, // 'bdlt::DatetimeInterval', capable of representing the (signed) difference // between two arbitrary points in time. The time interval represented by a // 'bdlt::DatetimeInterval' object has microsecond resolution. // ///The Representation of a Time Interval ///------------------------------------- // A time interval has a value that is independent of its representation. // Conceptually, the interval between two points in time could be described // using a (signed) real number of seconds (or minutes, or hours, etc.). A // 'bdlt::DatetimeInterval' represents this value as six fields: days, hours, // minutes, seconds, milliseconds, and microseconds. In the "canonical // representation" of a time interval, the days field may have any 32-bit // signed integer value, with the hours, minutes, seconds, milliseconds, and // microseconds fields limited to the respective ranges '[-23 .. 23]', // '[-59 .. 59]', '[-59 .. 59]', '[-999 .. 999]', and '[-999 .. 999]', with the // additional constraint that the six fields are either all non-negative or all // non-positive. When setting the value of a time interval via its six-field // representation, any integer value may be used in any field, with the // constraint that the resulting number of days be representable as a 32-bit // signed integer. Similarly, the field values may be accessed in the // canonical representation using the 'days', 'hours', 'minutes', 'seconds', // 'milliseconds', and 'microseconds' methods. // // The primary accessors for this type are 'days' and // 'fractionalDayInMicroseconds'. In combination, these two methods provide // complete and succinct access to the value of a 'DatetimeInterval'. // Furthermore, the total value of the interval may be accessed in the // respective field units via the 'totalDays', 'totalHours', 'totalMinutes', // 'totalSeconds', 'totalMilliseconds', and 'totalMicroseconds' methods. Note // that, with the exception of 'totalMicroseconds' (which returns an exact // result), the other "total" accessors round toward 0. Also note that the // 'totalMicroseconds' accessor can fail for extreme 'DatetimeInterval' values. // // The following summarizes the canonical representation of the value of a // 'bdlt::DatetimeInterval': //.. // Field Name Max. Valid Range Auxiliary Conditions Limiting Validity // ---------- ------------------ -------------------------------------- // days any 32-bit integer all fields non-pos. or all non-neg. // hours [ -23 .. 23] all fields non-pos. or all non-neg. // minutes [ -59 .. 59] all fields non-pos. or all non-neg. // seconds [ -59 .. 59] all fields non-pos. or all non-neg. // milliseconds [-999 .. 999] all fields non-pos. or all non-neg. // microseconds [-999 .. 999] all fields non-pos. or all non-neg. //.. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Basic 'bdlt::DatetimeInterval' Usage ///- - - - - - - - - - - - - - - - - - - - - - - - // This example demonstrates how to create and use a 'bdlt::DatetimeInterval' // object. // // First, create an object 'i1' having the default value: //.. // bdlt::DatetimeInterval i1; assert( 0 == i1.days()); // assert( 0 == i1.hours()); // assert( 0 == i1.minutes()); // assert( 0 == i1.seconds()); // assert( 0 == i1.milliseconds()); // assert( 0 == i1.microseconds()); //.. // Then, set the value of 'i1' to -5 days, and then add 16 hours to that value: //.. // i1.setTotalDays(-5); // i1.addHours(16); assert( -4 == i1.days()); // assert( -8 == i1.hours()); // assert( 0 == i1.minutes()); // assert( 0 == i1.seconds()); // assert( 0 == i1.milliseconds()); // assert( 0 == i1.microseconds()); //.. // Next, create 'i2' as a copy of 'i1': //.. // bdlt::DatetimeInterval i2(i1); assert( -4 == i2.days()); // assert( -8 == i2.hours()); // assert( 0 == i2.minutes()); // assert( 0 == i2.seconds()); // assert( 0 == i2.milliseconds()); // assert( 0 == i2.microseconds()); //.. // Then, add 2 days and 4 seconds to the value of 'i2' (in two steps), and // confirm that 'i2' has a value that is greater than that of 'i1': //.. // i2.addDays(2); // i2.addSeconds(4); assert( -2 == i2.days()); // assert( -7 == i2.hours()); // assert(-59 == i2.minutes()); // assert(-56 == i2.seconds()); // assert( 0 == i2.milliseconds()); // assert( 0 == i2.microseconds()); // assert(i2 > i1); //.. // Next, add 2 days and 4 seconds to the value of 'i1' in one step by using the // 'addInterval' method, and confirm that 'i1' now has the same value as 'i2': //.. // i1.addInterval(2, 0, 0, 4); assert(i2 == i1); //.. // Finally, write the value of 'i2' to 'stdout': //.. // bsl::cout << i2 << bsl::endl; //.. // The output operator produces the following format on 'stdout': //.. // -2_07:59:56.000000 //.. #include <bdlscm_version.h> #include <bdlt_timeunitratio.h> #include <bslh_hash.h> #include <bslmf_integralconstant.h> #include <bslmf_istriviallycopyable.h> #include <bsls_assert.h> #include <bsls_atomic.h> #include <bsls_log.h> #include <bsls_performancehint.h> #include <bsls_platform.h> #include <bsls_review.h> #include <bsls_timeinterval.h> #include <bsls_types.h> #include <bsl_cstdint.h> #include <bsl_limits.h> #include <bsl_iosfwd.h> namespace BloombergLP { namespace bdlt { // ====================== // class DatetimeInterval // ====================== class DatetimeInterval { // Each object of this class represents a (signed) time interval with // microsecond resolution. See {The Representation of a Time Interval} for // details. // PRIVATE TYPES typedef bsls::Types::Int64 Int64; enum { k_DEFAULT_FRACTIONAL_SECOND_PRECISION = 6 }; // DATA int32_t d_days; // field for days bsls::Types::Int64 d_microseconds; // field for fractional day // FRIENDS friend DatetimeInterval operator-(const DatetimeInterval&); friend bool operator==(const DatetimeInterval&, const DatetimeInterval&); friend bool operator!=(const DatetimeInterval&, const DatetimeInterval&); friend bool operator< (const DatetimeInterval&, const DatetimeInterval&); friend bool operator<=(const DatetimeInterval&, const DatetimeInterval&); friend bool operator> (const DatetimeInterval&, const DatetimeInterval&); friend bool operator>=(const DatetimeInterval&, const DatetimeInterval&); template <class HASHALG> friend void hashAppend(HASHALG&, const DatetimeInterval&); // PRIVATE MANIPULATORS void assign(bsls::Types::Int64 days, bsls::Types::Int64 microseconds); // Set this datetime interval to have the value given by the sum of the // specified 'days' and 'microseconds'. The behavior is undefined // unless the total number of days, after converting to the canonical // representation, can be represented as an 'int'. Note that it is // impossible for an 'Int64' to represent more than a day in // microseconds. Also note that the arguments may be supplied using a // mixture of positive, negative, and 0 values. int assignIfValid(bsls::Types::Int64 days, bsls::Types::Int64 microseconds); // Set this datetime interval to have the value given by the sum of the // specified 'days' and 'microseconds'. Return 0 if the total number // of days, after converting to the canonical representation, can be // represented as an 'int' and a non-zero value (with no effect) // otherwise. Note that it is impossible for an 'Int64' to represent // more than a day in microseconds. Also note that the arguments may // be supplied using a mixture of positive, negative, and 0 values. public: // PUBLIC CLASS DATA static const bsls::Types::Int64 k_MILLISECONDS_MAX = 185542587187199999LL; // The maximum interval that is representable by a 'DatetimeInterval', // in milliseconds. static const bsls::Types::Int64 k_MILLISECONDS_MIN = -k_MILLISECONDS_MAX - TimeUnitRatio::k_MILLISECONDS_PER_DAY; // The minimum interval that is representable by a 'DatetimeInterval', // in milliseconds. // CLASS METHODS static bool isValid(int days, bsls::Types::Int64 hours = 0, bsls::Types::Int64 minutes = 0, bsls::Types::Int64 seconds = 0, bsls::Types::Int64 milliseconds = 0, bsls::Types::Int64 microseconds = 0); // Return 'true' if a time interval object having the value given by // the specified 'days', and the optionally specified 'hours', // 'minutes', 'seconds', 'milliseconds', and 'microseconds' can be // represented as a 'DatetimeInterval' and 'false' otherwise. // Unspecified arguments default to 0. The resulting time interval // value is valid if the days field does not overflow a 32-bit integer. // Note that the arguments may be supplied using a mixture of positive, // negative, and 0 values. // Aspects static int maxSupportedBdexVersion(int versionSelector); // Return the maximum valid BDEX format version, as indicated by the // specified 'versionSelector', to be passed to the 'bdexStreamOut' // method. Note that it is highly recommended that 'versionSelector' // be formatted as "YYYYMMDD", a date representation. Also note that // 'versionSelector' should be a *compile*-time-chosen value that // selects a format version supported by both externalizer and // unexternalizer. See the 'bslx' package-level documentation for more // information on BDEX streaming of value-semantic types and // containers. // CREATORS DatetimeInterval(); // Create a time interval object having the value 0. explicit DatetimeInterval(int days, bsls::Types::Int64 hours = 0, bsls::Types::Int64 minutes = 0, bsls::Types::Int64 seconds = 0, bsls::Types::Int64 milliseconds = 0, bsls::Types::Int64 microseconds = 0); // Create a time interval object having the value given by the // specified 'days', and the optionally specified 'hours', 'minutes', // 'seconds', 'milliseconds', and 'microseconds'. Unspecified // arguments default to 0. The behavior is undefined unless the // resulting time interval value is valid (i.e., the days field must // not overflow a 32-bit integer). Note that the arguments may be // supplied using a mixture of positive, negative, and 0 values. DatetimeInterval(const DatetimeInterval& original); // Create a time interval object having the value of the specified // 'original' time interval. //! ~DatetimeInterval() = default; // Destroy this time interval object. Note that this method's // definition is generated by the compiler. // MANIPULATORS DatetimeInterval& operator=(const DatetimeInterval& rhs); // Assign to this object the value of the specified 'rhs' time // interval, and return a reference providing modifiable access to this // object. DatetimeInterval& operator+=(const DatetimeInterval& rhs); // Add to this time interval the value of the specified 'rhs' time // interval, and return a reference providing modifiable access to this // object. The behavior is undefined unless the resulting time // interval value is valid (i.e., the days field must not overflow a // 32-bit integer). DatetimeInterval& operator-=(const DatetimeInterval& rhs); // Subtract from this time interval the value of the specified 'rhs' // time interval, and return a reference providing modifiable access to // this object. The behavior is undefined unless the resulting time // interval value is valid (i.e., the days field must not overflow a // 32-bit integer). void setInterval(int days, bsls::Types::Int64 hours = 0, bsls::Types::Int64 minutes = 0, bsls::Types::Int64 seconds = 0, bsls::Types::Int64 milliseconds = 0, bsls::Types::Int64 microseconds = 0); // Set the time interval represented by this object to the value given // by the specified 'days', and the optionally specified 'hours', // 'minutes', 'seconds', 'milliseconds', and 'microseconds'. // Unspecified arguments default to 0. The behavior is undefined // unless the resulting time interval value is valid (i.e., the days // field must not overflow a 32-bit integer). Note that the arguments // may be supplied using a mixture of positive, negative, and 0 values. int setIntervalIfValid(int days, bsls::Types::Int64 hours = 0, bsls::Types::Int64 minutes = 0, bsls::Types::Int64 seconds = 0, bsls::Types::Int64 milliseconds = 0, bsls::Types::Int64 microseconds = 0); // Set the time interval represented by this object to the value given // by the specified 'days', and the optionally specified 'hours', // 'minutes', 'seconds', 'milliseconds', and 'microseconds'. // Unspecified arguments default to 0. Return 0 if the resulting time // interval value is valid (i.e., the 'days' field must not overflow an // 'int') and a non-zero value (with no effect) otherwise. Note that // the arguments may be supplied using a mixture of positive, negative, // and 0 values. void setTotalDays(int days); // Set the overall value of this object to indicate the specified // number of 'days'. void setTotalHours(bsls::Types::Int64 hours); // Set the overall value of this object to indicate the specified // number of 'hours'. The behavior is undefined unless the resulting // time interval value is valid (i.e., the days field must not overflow // a 32-bit integer). int setTotalHoursIfValid(bsls::Types::Int64 hours); // Set the overall value of this object to indicate the specified // number of 'hours'. Return 0 if the resulting time interval value is // valid (i.e., the 'days' field must not overflow an 'int') and a // non-zero value (with no effect) otherwise. void setTotalMinutes(bsls::Types::Int64 minutes); // Set the overall value of this object to indicate the specified // number of 'minutes'. The behavior is undefined unless the resulting // time interval value is valid (i.e., the days field must not overflow // a 32-bit integer). int setTotalMinutesIfValid(bsls::Types::Int64 minutes); // Set the overall value of this object to indicate the specified // number of 'minutes'. Return 0 if the resulting time interval value // is valid (i.e., the 'days' field must not overflow an 'int') and a // non-zero value (with no effect) otherwise. void setTotalSeconds(bsls::Types::Int64 seconds); // Set the overall value of this object to indicate the specified // number of 'seconds'. The behavior is undefined unless the resulting // time interval value is valid (i.e., the days field must not overflow // a 32-bit integer). int setTotalSecondsIfValid(bsls::Types::Int64 seconds); // Set the overall value of this object to indicate the specified // number of 'seconds'. Return 0 if the resulting time interval value // is valid (i.e., the 'days' field must not overflow an 'int') and a // non-zero value (with no effect) otherwise. void setTotalSecondsFromDouble(double seconds); // Set the overall value of this object to indicate the specified // number of 'seconds'. The fractional part of 'seconds', if any, is // rounded to the nearest whole number of microseconds. The behavior // is undefined unless the resulting time interval value is valid // (i.e., the days field must not overflow a 32-bit integer). int setTotalSecondsFromDoubleIfValid(double seconds); // Set the overall value of this object to indicate the specified // number of 'seconds'. The fractional part of 'seconds', if any, is // rounded to the nearest whole number of microseconds. Return 0 if // the resulting time interval value is valid (i.e., the 'days' field // must not overflow an 'int') and a non-zero value (with no effect) // otherwise. void setTotalMilliseconds(bsls::Types::Int64 milliseconds); // Set the overall value of this object to indicate the specified // number of 'milliseconds'. The behavior is undefined unless the // resulting time interval value is valid (i.e., the days field must // not overflow a 32-bit integer). int setTotalMillisecondsIfValid(bsls::Types::Int64 milliseconds); // Set the overall value of this object to indicate the specified // number of 'milliseconds'. Return 0 if the resulting time interval // value is valid (i.e., the days field must not overflow an 'int') and // a non-zero value (with no effect) otherwise. void setTotalMicroseconds(bsls::Types::Int64 microseconds); // Set the overall value of this object to indicate the specified // number of 'microseconds'. Note that there is no // 'setTotalMicrosecondsIfValid' because no value of 'microseconds' can // cause the number of days to overflow. DatetimeInterval& addInterval(int days, bsls::Types::Int64 hours = 0, bsls::Types::Int64 minutes = 0, bsls::Types::Int64 seconds = 0, bsls::Types::Int64 milliseconds = 0, bsls::Types::Int64 microseconds = 0); // Add to this time interval the specified number of 'days', and the // optionally specified number of 'hours', 'minutes', 'seconds', // 'milliseconds', and 'microseconds', and return a reference providing // modifiable access to this object. Unspecified arguments default to // 0. The behavior is undefined unless the resulting time interval // value is valid (i.e., the days field must not overflow a 32-bit // integer). Note that the arguments may be supplied using a mixture // of positive, negative, and 0 values. int addIntervalIfValid(int days, bsls::Types::Int64 hours = 0, bsls::Types::Int64 minutes = 0, bsls::Types::Int64 seconds = 0, bsls::Types::Int64 milliseconds = 0, bsls::Types::Int64 microseconds = 0); // Add to this time interval the specified number of 'days', and the // optionally specified number of 'hours', 'minutes', 'seconds', // 'milliseconds', and 'microseconds'. Return 0 if the resulting time // interval value is valid (i.e., the days field must not overflow an // 'int') and a non-zero value (with no effect) otherwise. Note that // the arguments may be supplied using a mixture of positive, negative, // and 0 values. DatetimeInterval& addDays(int days); // Add to this time interval the specified number of 'days', and return // a reference providing modifiable access to this object. The // behavior is undefined unless the resulting time interval value is // valid (i.e., the days field must not overflow a 32-bit integer). int addDaysIfValid(int days); // Add to this time interval the specified number of 'days'. Return 0 // if the resulting time interval value is valid (i.e., the days field // must not overflow an 'int') and a non-zero value (with no effect) // otherwise. DatetimeInterval& addHours(bsls::Types::Int64 hours); // Add to this time interval the specified number of 'hours', and // return a reference providing modifiable access to this object. The // behavior is undefined unless the resulting time interval value is // valid (i.e., the days field must not overflow a 32-bit integer). int addHoursIfValid(bsls::Types::Int64 hours); // Add to this time interval the specified number of 'hours'. Return 0 // if the resulting time interval value is valid (i.e., the days field // must not overflow an 'int') and a non-zero value (with no effect) // otherwise. DatetimeInterval& addMinutes(bsls::Types::Int64 minutes); // Add to this time interval the specified number of 'minutes', and // return a reference providing modifiable access to this object. The // behavior is undefined unless the resulting time interval value is // valid (i.e., the days field must not overflow a 32-bit integer). int addMinutesIfValid(bsls::Types::Int64 minutes); // Add to this time interval the specified number of 'minutes'. Return // 0 if the resulting time interval value is valid (i.e., the days // field must not overflow an 'int') and a non-zero value (with no // effect) otherwise. DatetimeInterval& addSeconds(bsls::Types::Int64 seconds); // Add to this time interval the specified number of 'seconds', and // return a reference providing modifiable access to this object. The // behavior is undefined unless the resulting time interval value is // valid (i.e., the days field must not overflow a 32-bit integer). int addSecondsIfValid(bsls::Types::Int64 seconds); // Add to this time interval the specified number of 'seconds'. Return // 0 if the resulting time interval value is valid (i.e., the days // field must not overflow an 'int') and a non-zero value (with no // effect) otherwise. DatetimeInterval& addMilliseconds(bsls::Types::Int64 milliseconds); // Add to this time interval the specified number of 'milliseconds', // and return a reference providing modifiable access to this object. // The behavior is undefined unless the resulting time interval value // is valid (i.e., the days field must not overflow a 32-bit integer). int addMillisecondsIfValid(bsls::Types::Int64 milliseconds); // Add to this time interval the specified number of 'milliseconds'. // Return 0 if the resulting time interval value is valid (i.e., the // days field must not overflow an 'int') and a non-zero value (with no // effect) otherwise. DatetimeInterval& addMicroseconds(bsls::Types::Int64 microseconds); // Add to this time interval the specified number of 'microseconds', // and return a reference providing modifiable access to this object. // The behavior is undefined unless the resulting time interval value // is valid (i.e., the days field must not overflow a 32-bit integer). int addMicrosecondsIfValid(bsls::Types::Int64 microseconds); // Add to this time interval the specified number of 'microseconds'. // Return 0 if the resulting time interval value is valid (i.e., the // days field must not overflow an 'int') and a non-zero value (with no // effect) otherwise. // Aspects template <class STREAM> STREAM& bdexStreamIn(STREAM& stream, int version); // Assign to this object the value read from the specified input // 'stream' using the specified 'version' format, and return a // reference to 'stream'. If 'stream' is initially invalid, this // operation has no effect. If 'version' is not supported, this object // is unaltered and 'stream' is invalidated, but otherwise unmodified. // If 'version' is supported but 'stream' becomes invalid during this // operation, this object has an undefined, but valid, state. Note // that no version is read from 'stream'. See the 'bslx' package-level // documentation for more information on BDEX streaming of // value-semantic types and containers. // ACCESSORS int days() const; // Return the days field in the canonical representation of the value // of this time interval. Note that the return value may be negative. // Also note that the return value is the same as that returned by // 'totalDays'. bsls::Types::Int64 fractionalDayInMicroseconds() const; // Return the value of this time interval as an integral number of // microseconds modulo the number of microseconds in a day. Note that // the return value may be negative. int hours() const; // Return the hours field in the canonical representation of the value // of this time interval. Note that the return value may be negative. int minutes() const; // Return the minutes field in the canonical representation of the // value of this time interval. Note that the return value may be // negative. int seconds() const; // Return the seconds field in the canonical representation of the // value of this time interval. Note that the return value may be // negative. int milliseconds() const; // Return the milliseconds field in the canonical representation of the // value of this time interval. Note that the return value may be // negative. int microseconds() const; // Return the microseconds field in the canonical representation of the // value of this time interval. Note that the return value may be // negative. int printToBuffer(char *result, int numBytes, int fractionalSecondPrecision = 6) const; // Efficiently write to the specified 'result' buffer no more than the // specified 'numBytes' of a representation of the value of this // object. Optionally specify 'fractionalSecondPrecision' digits to // indicate how many fractional second digits to output. If // 'fractionalSecondPrecision' is not specified then 6 fractional // second digits will be output (3 digits for milliseconds and 3 digits // for microseconds). Return the number of characters (not including // the null character) that would have been written if the limit due to // 'numBytes' were not imposed. 'result' is null-terminated unless // 'numBytes' is 0. The behavior is undefined unless '0 <= numBytes', // '0 <= fractionalSecondPrecision <= 6', and 'result' refers to at // least 'numBytes' contiguous bytes. Note that the return value is // greater than or equal to 'numBytes' if the output representation was // truncated to avoid 'result' overrun. int totalDays() const; // Return the value of this time interval in integral days, rounded // toward 0. Note that the return value may be negative. Also note // that the return value is the same as that returned by 'days'. bsls::Types::Int64 totalHours() const; // Return the value of this time interval in integral hours, rounded // toward 0. Note that the return value may be negative. bsls::Types::Int64 totalMinutes() const; // Return the value of this time interval in integral minutes, rounded // toward 0. Note that the return value may be negative. bsls::Types::Int64 totalSeconds() const; // Return the value of this time interval in integral seconds, rounded // toward 0. Note that the return value may be negative. double totalSecondsAsDouble() const; // Return the value of this time interval in seconds as a 'double', // potentially with a fractional part. Note that the return value may // be negative. Also note that the conversion from the internal // representation to 'double' may *lose* precision. bsls::Types::Int64 totalMilliseconds() const; // Return the value of this time interval in integral milliseconds, // rounded towards zero. Note that the return value may be negative. bsls::Types::Int64 totalMicroseconds() const; // Return the value of this time interval as an integral number of // microseconds. The behavior is undefined unless the number of // microseconds can be represented with a 64-bit signed integer. Note // that the return value may be negative. // Aspects template <class STREAM> STREAM& bdexStreamOut(STREAM& stream, int version) const; // Write the value of this object, using the specified 'version' // format, to the specified output 'stream', and return a reference to // 'stream'. If 'stream' is initially invalid, this operation has no // effect. If 'version' is not supported, 'stream' is invalidated, but // otherwise unmodified. Note that 'version' is not written to // 'stream'. See the 'bslx' package-level documentation for more // information on BDEX streaming of value-semantic types and // containers. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Write the value of this object to the specified output 'stream' in a // human-readable format, and return a reference to 'stream'. // Optionally specify an initial indentation 'level', whose absolute // value is incremented recursively for nested objects. If 'level' is // specified, optionally specify 'spacesPerLevel', whose absolute value // indicates the number of spaces per indentation level for this and // all of its nested objects. If 'level' is negative, suppress // indentation of the first line. If 'spacesPerLevel' is negative, // format the entire output on one line, suppressing all but the // initial indentation (as governed by 'level'). If 'stream' is not // valid on entry, this operation has no effect. Note that the format // is not fully specified, and can change without notice. #ifndef BDE_OPENSOURCE_PUBLICATION // pending deprecation // DEPRECATED METHODS static int maxSupportedBdexVersion(); // !DEPRECATED!: Use 'maxSupportedBdexVersion(int)' instead. // // Return the most current BDEX streaming version number supported by // this class. #endif // BDE_OPENSOURCE_PUBLICATION -- pending deprecation #ifndef BDE_OMIT_INTERNAL_DEPRECATED // BDE2.22 static int maxSupportedVersion(); // !DEPRECATED!: Use 'maxSupportedBdexVersion(int)' instead. // // Return the most current BDEX streaming version number supported by // this class. bsl::ostream& streamOut(bsl::ostream& stream) const; // !DEPRECATED!: use 'operator<<' or 'print' instead. // // Format this datetime interval to the specified output 'stream', and // return a reference to 'stream'. #endif // BDE_OMIT_INTERNAL_DEPRECATED -- BDE2.22 }; // FREE OPERATORS DatetimeInterval operator+(const DatetimeInterval& lhs, const DatetimeInterval& rhs); // Return a 'DatetimeInterval' object whose value is the sum of the // specified 'lhs' and 'rhs' time intervals. The behavior is undefined // unless the resulting time interval value is valid (i.e., the days field // must not overflow a 32-bit integer). DatetimeInterval operator-(const DatetimeInterval& lhs, const DatetimeInterval& rhs); // Return a 'DatetimeInterval' object whose value is the difference between // the specified 'lhs' and 'rhs' time intervals. The behavior is undefined // unless the resulting time interval value is valid (i.e., the days field // must not overflow a 32-bit integer). DatetimeInterval operator-(const DatetimeInterval& value); // Return a 'DatetimeInterval' object whose value is the negative of the // specified time interval 'value'. The behavior is undefined unless // 'INT_MIN < value.days()'. bool operator==(const DatetimeInterval& lhs, const DatetimeInterval& rhs); // Return 'true' if the specified 'lhs' and 'rhs' time intervals have the // same value, and 'false' otherwise. Two time intervals have the same // value if all of the corresponding values of their days, hours, minutes, // seconds, milliseconds, and microseconds fields are the same. bool operator!=(const DatetimeInterval& lhs, const DatetimeInterval& rhs); // Return 'true' if the specified 'lhs' and 'rhs' time intervals do not // have the same value, and 'false' otherwise. Two time intervals do not // have the same value if any of the corresponding values of their days, // hours, minutes, seconds, milliseconds, or microseconds fields is not // the same. bool operator< (const DatetimeInterval& lhs, const DatetimeInterval& rhs); bool operator<=(const DatetimeInterval& lhs, const DatetimeInterval& rhs); bool operator> (const DatetimeInterval& lhs, const DatetimeInterval& rhs); bool operator>=(const DatetimeInterval& lhs, const DatetimeInterval& rhs); // Return 'true' if the nominal relation between the specified 'lhs' and // 'rhs' time interval values holds, and 'false' otherwise. 'lhs' is less // than 'rhs' if the following expression evaluates to 'true': //.. // lhs.days() < rhs.days() // || (lhs.days() == rhs.days() && lhs.fractionalDayInMicroseconds() // < rhs.fractionalDayInMicroseconds()) //.. // The other relationships are defined similarly. bsl::ostream& operator<<(bsl::ostream& stream, const DatetimeInterval& object); // Write the value of the specified 'object' to the specified output // 'stream' in a single-line format, and return a reference providing // modifiable access to 'stream'. If 'stream' is not valid on entry, this // operation has no effect. Note that this human-readable format is not // fully specified and can change without notice. Also note that this // method has the same behavior as 'object.print(stream, 0, -1)'. // FREE FUNCTIONS template <class HASHALG> void hashAppend(HASHALG& hashAlg, const DatetimeInterval& object); // Pass the specified 'object' to the specified 'hashAlg'. This function // integrates with the 'bslh' modular hashing system and effectively // provides a 'bsl::hash' specialization for 'DatetimeInterval'. // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ---------------------- // class DatetimeInterval // ---------------------- // CLASS METHODS // Aspects inline int DatetimeInterval::maxSupportedBdexVersion(int versionSelector) { if (versionSelector >= 20170401) { return 2; // RETURN } return 1; } // CREATORS inline DatetimeInterval::DatetimeInterval() : d_days(0) , d_microseconds(0) { } inline DatetimeInterval::DatetimeInterval(int days, bsls::Types::Int64 hours, bsls::Types::Int64 minutes, bsls::Types::Int64 seconds, bsls::Types::Int64 milliseconds, bsls::Types::Int64 microseconds) { setInterval(days, hours, minutes, seconds, milliseconds, microseconds); } inline DatetimeInterval::DatetimeInterval(const DatetimeInterval& original) : d_days(original.d_days) , d_microseconds(original.d_microseconds) { } // MANIPULATORS inline DatetimeInterval& DatetimeInterval::operator=(const DatetimeInterval& rhs) { d_days = rhs.d_days; d_microseconds = rhs.d_microseconds; return *this; } inline DatetimeInterval& DatetimeInterval::operator+=(const DatetimeInterval& rhs) { #ifdef BSLS_ASSERT_IS_USED int rc = addIntervalIfValid(rhs.d_days, 0, 0, 0, 0, rhs.d_microseconds); BSLS_ASSERT(0 == rc && "operator+= over/under flow"); (void) rc; #else addInterval(rhs.d_days, 0, 0, 0, 0, rhs.d_microseconds); #endif return *this; } inline DatetimeInterval& DatetimeInterval::operator-=(const DatetimeInterval& rhs) { Int64 rhsDays = rhs.d_days; Int64 rhsMicroseconds = rhs.d_microseconds; if (INT_MIN == rhsDays) { ++rhsDays; rhsMicroseconds -= TimeUnitRatio::k_US_PER_D; } rhsDays = -rhsDays; rhsMicroseconds = -rhsMicroseconds; BSLS_ASSERT_SAFE(rhsDays <= INT_MAX && INT_MIN < rhsDays); // always true #ifdef BSLS_ASSERT_IS_USED int rc = addIntervalIfValid( static_cast<int>(rhsDays), 0, 0, 0, 0, rhsMicroseconds); BSLS_ASSERT(0 == rc && "operator-= over/under flow"); (void) rc; #else addInterval(static_cast<int>(rhsDays), 0, 0, 0, 0, rhsMicroseconds); #endif return *this; } inline void DatetimeInterval::setTotalDays(int days) { d_days = days; d_microseconds = 0; } inline void DatetimeInterval::setTotalHours(bsls::Types::Int64 hours) { assign(hours / TimeUnitRatio::k_H_PER_D, hours % TimeUnitRatio::k_H_PER_D * TimeUnitRatio::k_US_PER_H); } inline int DatetimeInterval::setTotalHoursIfValid(bsls::Types::Int64 hours) { return assignIfValid(hours / TimeUnitRatio::k_H_PER_D, (hours % TimeUnitRatio::k_H_PER_D) * TimeUnitRatio::k_US_PER_H); } inline void DatetimeInterval::setTotalMinutes(bsls::Types::Int64 minutes) { assign(minutes / TimeUnitRatio::k_M_PER_D, minutes % TimeUnitRatio::k_M_PER_D * TimeUnitRatio::k_US_PER_M); } inline int DatetimeInterval::setTotalMinutesIfValid(bsls::Types::Int64 minutes) { return assignIfValid(minutes / TimeUnitRatio::k_M_PER_D, (minutes % TimeUnitRatio::k_M_PER_D) * TimeUnitRatio::k_US_PER_M); } inline void DatetimeInterval::setTotalSeconds(bsls::Types::Int64 seconds) { assign(seconds / TimeUnitRatio::k_S_PER_D, seconds % TimeUnitRatio::k_S_PER_D * TimeUnitRatio::k_US_PER_S); } inline int DatetimeInterval::setTotalSecondsIfValid(bsls::Types::Int64 seconds) { return assignIfValid(seconds / TimeUnitRatio::k_S_PER_D, (seconds % TimeUnitRatio::k_S_PER_D) * TimeUnitRatio::k_US_PER_S); } inline void DatetimeInterval::setTotalMilliseconds(bsls::Types::Int64 milliseconds) { assign(milliseconds / TimeUnitRatio::k_MS_PER_D, milliseconds % TimeUnitRatio::k_MS_PER_D * TimeUnitRatio::k_US_PER_MS); } inline int DatetimeInterval::setTotalMillisecondsIfValid( bsls::Types::Int64 milliseconds) { return assignIfValid(milliseconds / TimeUnitRatio::k_MS_PER_D, (milliseconds % TimeUnitRatio::k_MS_PER_D) * TimeUnitRatio::k_US_PER_MS); } inline void DatetimeInterval::setTotalMicroseconds(bsls::Types::Int64 microseconds) { assign(microseconds / TimeUnitRatio::k_US_PER_D, microseconds % TimeUnitRatio::k_US_PER_D); } inline DatetimeInterval& DatetimeInterval::addDays(int days) { assign(static_cast<bsls::Types::Int64>(d_days) + static_cast<bsls::Types::Int64>(days), d_microseconds); return *this; } inline int DatetimeInterval::addDaysIfValid(int days) { return assignIfValid(static_cast<bsls::Types::Int64>(d_days) + static_cast<bsls::Types::Int64>(days), d_microseconds); } inline DatetimeInterval& DatetimeInterval::addHours(bsls::Types::Int64 hours) { assign(static_cast<bsls::Types::Int64>(d_days) + hours / TimeUnitRatio::k_H_PER_D, d_microseconds + hours % TimeUnitRatio::k_H_PER_D * TimeUnitRatio::k_US_PER_H); return *this; } inline int DatetimeInterval::addHoursIfValid(bsls::Types::Int64 hours) { return assignIfValid(static_cast<bsls::Types::Int64>(d_days) + hours / TimeUnitRatio::k_H_PER_D, d_microseconds + (hours % TimeUnitRatio::k_H_PER_D) * TimeUnitRatio::k_US_PER_H); } inline DatetimeInterval& DatetimeInterval::addMinutes(bsls::Types::Int64 minutes) { assign(static_cast<bsls::Types::Int64>(d_days) + minutes / TimeUnitRatio::k_M_PER_D, d_microseconds + minutes % TimeUnitRatio::k_M_PER_D * TimeUnitRatio::k_US_PER_M); return *this; } inline int DatetimeInterval::addMinutesIfValid(bsls::Types::Int64 minutes) { return assignIfValid(static_cast<bsls::Types::Int64>(d_days) + minutes / TimeUnitRatio::k_M_PER_D, d_microseconds + (minutes % TimeUnitRatio::k_M_PER_D) * TimeUnitRatio::k_US_PER_M); } inline DatetimeInterval& DatetimeInterval::addSeconds(bsls::Types::Int64 seconds) { assign(static_cast<bsls::Types::Int64>(d_days) + seconds / TimeUnitRatio::k_S_PER_D, d_microseconds + seconds % TimeUnitRatio::k_S_PER_D * TimeUnitRatio::k_US_PER_S); return *this; } inline int DatetimeInterval::addSecondsIfValid(bsls::Types::Int64 seconds) { return assignIfValid(static_cast<bsls::Types::Int64>(d_days) + seconds / TimeUnitRatio::k_S_PER_D, d_microseconds + (seconds % TimeUnitRatio::k_S_PER_D) * TimeUnitRatio::k_US_PER_S); } inline DatetimeInterval& DatetimeInterval::addMilliseconds(bsls::Types::Int64 milliseconds) { assign(static_cast<bsls::Types::Int64>(d_days) + milliseconds / TimeUnitRatio::k_MS_PER_D, d_microseconds + milliseconds % TimeUnitRatio::k_MS_PER_D * TimeUnitRatio::k_US_PER_MS); return *this; } inline int DatetimeInterval::addMillisecondsIfValid(bsls::Types::Int64 milliseconds) { return assignIfValid(static_cast<bsls::Types::Int64>(d_days) + milliseconds / TimeUnitRatio::k_MS_PER_D, d_microseconds + (milliseconds % TimeUnitRatio::k_MS_PER_D) * TimeUnitRatio::k_US_PER_MS); } inline DatetimeInterval& DatetimeInterval::addMicroseconds(bsls::Types::Int64 microseconds) { assign(static_cast<bsls::Types::Int64>(d_days) + microseconds / TimeUnitRatio::k_US_PER_D, d_microseconds + microseconds % TimeUnitRatio::k_US_PER_D); return *this; } inline int DatetimeInterval::addMicrosecondsIfValid(bsls::Types::Int64 microseconds) { return assignIfValid(static_cast<bsls::Types::Int64>(d_days) + microseconds / TimeUnitRatio::k_US_PER_D, d_microseconds + microseconds % TimeUnitRatio::k_US_PER_D); } // Aspects template <class STREAM> STREAM& DatetimeInterval::bdexStreamIn(STREAM& stream, int version) { if (stream) { switch (version) { // switch on the schema version case 2: { int tmpDays; stream.getInt32(tmpDays); bsls::Types::Int64 tmpMicroseconds; stream.getInt64(tmpMicroseconds); if ( stream && ( (0 <= tmpDays && 0 <= tmpMicroseconds) || (0 >= tmpDays && 0 >= tmpMicroseconds)) && TimeUnitRatio::k_US_PER_D > tmpMicroseconds && -TimeUnitRatio::k_US_PER_D < tmpMicroseconds) { assign(tmpDays, tmpMicroseconds); } else { stream.invalidate(); } } break; case 1: { bsls::Types::Int64 tmp; stream.getInt64(tmp); if ( stream && k_MILLISECONDS_MIN <= tmp && k_MILLISECONDS_MAX >= tmp) { setTotalMilliseconds(tmp); } else { stream.invalidate(); } } break; default: { stream.invalidate(); // unrecognized version number } } } return stream; } // ACCESSORS inline int DatetimeInterval::days() const { return d_days; } inline bsls::Types::Int64 DatetimeInterval::fractionalDayInMicroseconds() const { return d_microseconds; } inline int DatetimeInterval::hours() const { return static_cast<int>(d_microseconds / TimeUnitRatio::k_US_PER_H); } inline int DatetimeInterval::minutes() const { return static_cast<int>(d_microseconds / TimeUnitRatio::k_US_PER_M % TimeUnitRatio::k_M_PER_H); } inline int DatetimeInterval::seconds() const { return static_cast<int>(d_microseconds / TimeUnitRatio::k_US_PER_S % TimeUnitRatio::k_S_PER_M); } inline int DatetimeInterval::milliseconds() const { return static_cast<int>(d_microseconds / TimeUnitRatio::k_US_PER_MS % TimeUnitRatio::k_MS_PER_S); } inline int DatetimeInterval::microseconds() const { return static_cast<int>(d_microseconds % TimeUnitRatio::k_US_PER_MS); } inline int DatetimeInterval::totalDays() const { return d_days; } inline bsls::Types::Int64 DatetimeInterval::totalHours() const { return static_cast<bsls::Types::Int64>(d_days) * TimeUnitRatio::k_H_PER_D + d_microseconds / TimeUnitRatio::k_US_PER_H; } inline bsls::Types::Int64 DatetimeInterval::totalMinutes() const { return static_cast<bsls::Types::Int64>(d_days) * TimeUnitRatio::k_M_PER_D + d_microseconds / TimeUnitRatio::k_US_PER_M; } inline bsls::Types::Int64 DatetimeInterval::totalSeconds() const { return static_cast<bsls::Types::Int64>(d_days) * TimeUnitRatio::k_S_PER_D + d_microseconds / TimeUnitRatio::k_US_PER_S; } inline double DatetimeInterval::totalSecondsAsDouble() const { return d_days * static_cast<double>(TimeUnitRatio::k_S_PER_D) + static_cast<double>(d_microseconds) / static_cast<double>(TimeUnitRatio::k_US_PER_S); } inline bsls::Types::Int64 DatetimeInterval::totalMilliseconds() const { return static_cast<bsls::Types::Int64>(d_days) * TimeUnitRatio::k_MS_PER_D + d_microseconds / TimeUnitRatio::k_US_PER_MS; } inline bsls::Types::Int64 DatetimeInterval::totalMicroseconds() const { BSLS_REVIEW( 0 >= d_days || (bsl::numeric_limits<bsls::Types::Int64>::max() - d_microseconds) / TimeUnitRatio::k_US_PER_D >= d_days); #if !defined(BSLS_PLATFORM_CMP_SUN) \ || !defined(BDE_BUILD_TARGET_OPT) \ || BSLS_PLATFORM_CMP_VERSION >= 0x5140 // Older versions of the Sun compiler (e.g., 5.12.3 and 5.12.4) fail to // compile the following 'BSLS_REVIEW' correctly in optimized builds. BSLS_REVIEW( 0 <= d_days || (bsl::numeric_limits<bsls::Types::Int64>::min() - d_microseconds) / TimeUnitRatio::k_US_PER_D <= d_days); #endif return static_cast<bsls::Types::Int64>(d_days) * TimeUnitRatio::k_US_PER_D + d_microseconds; } // Aspects template <class STREAM> STREAM& DatetimeInterval::bdexStreamOut(STREAM& stream, int version) const { if (stream) { switch (version) { // switch on the schema version case 2: { stream.putInt32(d_days); stream.putInt64(d_microseconds); } break; case 1: { stream.putInt64(totalMilliseconds()); } break; default: { stream.invalidate(); // unrecognized version number } } } return stream; } #ifndef BDE_OPENSOURCE_PUBLICATION // pending deprecation // DEPRECATED METHODS inline int DatetimeInterval::maxSupportedBdexVersion() { return maxSupportedBdexVersion(0); } #endif // BDE_OPENSOURCE_PUBLICATION -- pending deprecation #ifndef BDE_OMIT_INTERNAL_DEPRECATED // BDE2.22 inline int DatetimeInterval::maxSupportedVersion() { return maxSupportedBdexVersion(0); } #endif // BDE_OMIT_INTERNAL_DEPRECATED -- BDE2.22 } // close package namespace // FREE OPERATORS inline bdlt::DatetimeInterval bdlt::operator+(const DatetimeInterval& lhs, const DatetimeInterval& rhs) { DatetimeInterval ret(lhs); #ifdef BSLS_ASSERT_IS_USED int rc = ret.addIntervalIfValid(0, 0, 0, 0, rhs.totalMilliseconds(), rhs.microseconds()); BSLS_ASSERT(0 == rc && "operator+ over/under flow"); (void) rc; #else ret.addInterval(0, 0, 0, 0, rhs.totalMilliseconds(), rhs.microseconds()); #endif return ret; } inline bdlt::DatetimeInterval bdlt::operator-(const DatetimeInterval& lhs, const DatetimeInterval& rhs) { DatetimeInterval ret(lhs); #ifdef BSLS_ASSERT_IS_USED int rc = ret.addIntervalIfValid(0, 0, 0, 0, -rhs.totalMilliseconds(), -rhs.microseconds()); BSLS_ASSERT(0 == rc && "operator- over/under flow"); (void) rc; #else ret.addInterval(0, 0, 0, 0, -rhs.totalMilliseconds(), -rhs.microseconds()); #endif return ret; } inline bdlt::DatetimeInterval bdlt::operator-(const DatetimeInterval& value) { BSLS_REVIEW(value.d_days > bsl::numeric_limits<int32_t>::min()); DatetimeInterval interval; interval.d_days = -value.d_days; interval.d_microseconds = -value.d_microseconds; return interval; } inline bool bdlt::operator==(const DatetimeInterval& lhs, const DatetimeInterval& rhs) { return lhs.d_days == rhs.d_days && lhs.d_microseconds == rhs.d_microseconds; } inline bool bdlt::operator!=(const DatetimeInterval& lhs, const DatetimeInterval& rhs) { return lhs.d_days != rhs.d_days || lhs.d_microseconds != rhs.d_microseconds; } inline bool bdlt::operator< (const DatetimeInterval& lhs, const DatetimeInterval& rhs) { return lhs.d_days < rhs.d_days || ( lhs.d_days == rhs.d_days && lhs.d_microseconds < rhs.d_microseconds); } inline bool bdlt::operator<=(const DatetimeInterval& lhs, const DatetimeInterval& rhs) { return lhs.d_days < rhs.d_days || ( lhs.d_days == rhs.d_days && lhs.d_microseconds <= rhs.d_microseconds); } inline bool bdlt::operator> (const DatetimeInterval& lhs, const DatetimeInterval& rhs) { return lhs.d_days > rhs.d_days || ( lhs.d_days == rhs.d_days && lhs.d_microseconds > rhs.d_microseconds); } inline bool bdlt::operator>=(const DatetimeInterval& lhs, const DatetimeInterval& rhs) { return lhs.d_days > rhs.d_days || ( lhs.d_days == rhs.d_days && lhs.d_microseconds >= rhs.d_microseconds); } inline bsl::ostream& bdlt::operator<<(bsl::ostream& stream, const DatetimeInterval& object) { return object.print(stream, 0, -1); } // FREE FUNCTIONS template <class HASHALG> void bdlt::hashAppend(HASHALG& hashAlg, const DatetimeInterval& object) { using ::BloombergLP::bslh::hashAppend; hashAppend(hashAlg, object.d_days); hashAppend(hashAlg, object.d_microseconds); } } // close enterprise namespace namespace bsl { // TRAITS template <> struct is_trivially_copyable<BloombergLP::bdlt::DatetimeInterval> : bsl::true_type { // This template specialization for 'is_trivially_copyable' indicates that // 'DatetimeInterval' is a trivially copyable type. }; } // close namespace bsl #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 ----------------------------------