// bdlt_datetime.h -*-C++-*- #ifndef INCLUDED_BDLT_DATETIME #define INCLUDED_BDLT_DATETIME #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a value-semantic type representing both date and time. // //@CLASSES: // bdlt::Datetime: date and time value (at least microsecond resolution) // //@SEE_ALSO: bdlt_date, bdlt_time, bdlt_datetimetz // //@DESCRIPTION: This component implements a value-semantic type, // 'bdlt::Datetime', that represents the composition of a date and a time // value. The combined "date+time" value of a 'bdlt::Datetime' object is // expressed textually as "yyyy/mm/dd_hh:mm:ss.ssssss", where "yyyy/mm/dd" // represents the "date" part of the value and "hh:mm:ss.ssssss" represents the // "time" part. // // In addition to the usual value-semantic complement of methods for getting // and setting value, the 'bdlt::Datetime' class provides methods and operators // for making relative adjustments to value ('addDays', 'addTime', 'addHours', // etc.). In particular, note that adding units of time to a 'bdlt::Datetime' // object can affect the values of both the time and date parts of the object. // For example, invoking 'addHours(2)' on a 'bdlt::Datetime' object whose value // is "1987/10/03_22:30:00.000000" updates the value to // "1987/10/04_00:30:00.000000". // ///Valid 'bdlt::Datetime' Values and Their Representations ///------------------------------------------------------- // The "date" part of a 'bdlt::Datetime' value has a range of validity // identical to a 'bdlt::Date' object -- i.e., valid dates (according to the // Unix [POSIX] calendar) having years in the range '[1 .. 9999]'. The valid // time values are '[00:00:00.000000 .. 23:59:59.999999]'. Furthermore, the // unset time value (i.e., 24:00:00.000000, corresponding to the default // constructed value for 'bdlt::Time') is available for every valid date. Note // that the supported range of time does *not* allow for the injection of leap // seconds. The value "0001/01/01_24:00:00.000000" is the default constructed // value of 'bdlt::Datetime'. // // Furthermore, consistent with the 'bdlt::Time' type, a 'bdlt::Datetime' // object whose "time" part has the default constructed value, behaves the // same, with respect to manipulators and (most) free operators, as if the // "time" part had the value 00:00:00.000000. As for 'bdlt::Time', the // behavior of all 'bdlt::Datetime' relational comparison operators is // undefined if the "time" part of either operand is 24:00:00.000000. // Consequently, 'bdlt::Datetime' objects whose "time" part has the default // constructed value must *not* be used as keys for the standard associative // containers, since 'operator<' is not defined for such objects. // ///Attributes ///---------- // Conceptually, the two primary attributes of 'bdlt::Datetime' are the // constituent date and time values. These attributes are given the special // designation "part" in this component (i.e., the "time" part and the "date" // part, respectively) to distinguish them from the many other attributes (see // below) that derive from these two main parts. //.. // Name Related Type Default Range // ---- ------------ --------------- ------------------------------------ // date bdlt::Date 0001/01/01 [0001/01/01 .. 9999/12/31] // time bdlt::Time 24:00:00.000000 [00:00:00.000000 .. 23:59:59.999999] //.. // A 'bdlt::Datetime' object can be used in terms of its "date" and "time" // parts or, if appropriate to an application, the object can be viewed as a // single, integrated type having the combined individual attributes of date // and time. Accessors and manipulators are provided for each of these eight // (derived) attributes: //.. // Name Type Default Range Constraint // ----------- ---- ------- ----------- ----------------------------- // year int 1 [1 .. 9999] none // month int 1 [1 .. 12] none // day int 1 [1 .. 31] must exist for year and month // hour int 24 [0 .. 24] none // minute int 0 [0 .. 59] must be 0 if '24 == hour' // second int 0 [0 .. 59] must be 0 if '24 == hour' // millisecond int 0 [0 .. 999] must be 0 if '24 == hour' // microsecond int 0 [0 .. 999] must be 0 if '24 == hour' //.. // There are two additional "date" part attributes to 'bdlt::Datetime': //.. // Name Type Default Range Constraint // --------- --------------------- ------- ------------ ---------------------- // dayOfYear int 1 [ 1 .. 366] 366 only on leap years // dayOfWeek bdlt::DayOfWeek::Enum SAT [SUN .. SAT] tied to calendar day //.. // where 'dayOfYear' tracks the value of 'year/month/day' (and *vice* *versa*), // and 'dayOfWeek' can be accessed but not explicitly set. // ///ISO Standard Text Representation ///-------------------------------- // A common standard text representation of a date and time value is described // by ISO 8601. BDE provides the 'bdlt_iso8601util' component for conversion // to and from the standard ISO8601 format. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Basic Syntax ///- - - - - - - - - - - - // Values represented by objects of type 'bdlt::Datetime' are used widely in // practice. The values of the individual attributes resulting from a // default-constructed 'bdlt::Datetime' object, 'dt', are // "0001/01/01_24:00:00.000000": //.. // bdlt::Datetime dt; assert( 1 == dt.date().year()); // assert( 1 == dt.date().month()); // assert( 1 == dt.date().day()); // assert(24 == dt.hour()); // assert( 0 == dt.minute()); // assert( 0 == dt.second()); // assert( 0 == dt.millisecond()); // assert( 0 == dt.microsecond()); //.. // We can then set 'dt' to have a specific value, say, 8:43pm on January 6, // 2013: //.. // dt.setDatetime(2013, 1, 6, 20, 43); // assert(2013 == dt.date().year()); // assert( 1 == dt.date().month()); // assert( 6 == dt.date().day()); // assert( 20 == dt.hour()); // assert( 43 == dt.minute()); // assert( 0 == dt.second()); // assert( 0 == dt.millisecond()); // assert( 0 == dt.microsecond()); //.. // Now suppose we add 6 hours and 9 seconds to this value. There is more than // one way to do it: //.. // bdlt::Datetime dt2(dt); // dt2.addHours(6); // dt2.addSeconds(9); // assert(2013 == dt2.date().year()); // assert( 1 == dt2.date().month()); // assert( 7 == dt2.date().day()); // assert( 2 == dt2.hour()); // assert( 43 == dt2.minute()); // assert( 9 == dt2.second()); // assert( 0 == dt2.millisecond()); // assert( 0 == dt2.microsecond()); // // bdlt::Datetime dt3(dt); // dt3.addTime(6, 0, 9); // assert(dt2 == dt3); //.. // Notice that (in both cases) the date changed as a result of adding time; // however, changing just the date never affects the time: //.. // dt3.addDays(10); // assert(2013 == dt3.date().year()); // assert( 1 == dt3.date().month()); // assert( 17 == dt3.date().day()); // assert( 2 == dt3.hour()); // assert( 43 == dt3.minute()); // assert( 9 == dt3.second()); // assert( 0 == dt3.millisecond()); // assert( 0 == dt3.microsecond()); //.. // We can also add more than a day's worth of time: //.. // dt2.addHours(240); // assert(dt3 == dt2); //.. // The individual arguments can also be negative: //.. // dt2.addTime(-246, 0, -10, 1000); // -246 h, -10 s, +1000 ms // assert(dt == dt2); //.. // Finally, we stream the value of 'dt2' to 'stdout': //.. // bsl::cout << dt2 << bsl::endl; //.. // The streaming operator produces the following output on 'stdout': //.. // 06JAN2013_20:43:00.000000 //.. // ///Example 2: Creating a Schedule of Equal Time Intervals /// - - - - - - - - - - - - - - - - - - - - - - - - - - - // Calculations involving date and time values are difficult to get correct // manually; consequently, people tend to schedule events on natural time // boundaries (e.g., on the hour) even if that is sub-optimal. Having a class // such as 'bdlt::Datetime' makes doing date and time calculations trivial. // // Suppose one wants to divide into an arbitrary interval such as the time // between sunset and sunrise into an arbitrary number (say 7) of equal // intervals (perhaps to use as a duty roster for teams making astronomical // observations). // // First, we create objects containing values for the start and end of the time // interval: //.. // bdlt::Datetime sunset(2014, 6, 26, 20, 31, 23); // New York City // bdlt::Datetime sunrise(2014, 6, 27, 5, 26, 51); // New York City //.. // Then, we calculate the length of each shift in milliseconds (for good // precision -- we may be synchronizing astronomical instruments). Note that // the difference of 'sunrise' and 'sunset' creates a temporary // 'bdlt::DatetimeInterval' object: //.. // const int numShifts = 7; // const bsls::Types::Int64 shiftLengthInMsec // = (sunrise - sunset).totalMilliseconds() // / numShifts; //.. // Now, we calculate (and print to 'stdout') the beginning and end times for // each shift: //.. // for (int i = 0; i <= numShifts; ++i) { // bdlt::Datetime startOfShift(sunset); // startOfShift.addMilliseconds(shiftLengthInMsec * i); // bsl::cout << startOfShift << bsl::endl; // } //.. // Finally, we observe: //.. // 26JUN2014_20:31:23.000000 // 26JUN2014_21:47:52.714000 // 26JUN2014_23:04:22.428000 // 27JUN2014_00:20:52.142000 // 27JUN2014_01:37:21.856000 // 27JUN2014_02:53:51.570000 // 27JUN2014_04:10:21.284000 // 27JUN2014_05:26:50.998000 //.. // Notice how our objects (since they manage both "date" and "time of day" // parts of each point in time) seamlessly handle the transition between the // two days. #include <bdlscm_version.h> #include <bdlt_date.h> #include <bdlt_datetimeimputil.h> #include <bdlt_datetimeinterval.h> #include <bdlt_dayofweek.h> #include <bdlt_time.h> #include <bdlt_timeunitratio.h> #include <bdlb_bitutil.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_preconditions.h> #include <bsls_review.h> #include <bsls_stackaddressutil.h> #include <bsls_timeinterval.h> #include <bsls_types.h> #include <bsl_iosfwd.h> #include <bsl_cstring.h> // memset #include <bsl_sstream.h> namespace BloombergLP { namespace bdlt { // ============== // class Datetime // ============== class Datetime { // This class implements a simply-constrained value-semantic type // representing the composition of date and time values. Valid date values // for the "date" part of a 'Datetime' object are the same as those defined // for 'Date' objects; similarly, valid time values for the "time" part of // a 'Datetime' object are similar to those defined for 'Time' objects (but // with additional precision). Relational operators are disallowed on // 'Datetime' objects whose "time" part has the same value as that of a // default constructed 'Time' object. // PRIVATE TYPES enum { k_NUM_TIME_BITS = 37, k_DEFAULT_FRACTIONAL_SECOND_PRECISION = 6 }; // CLASS DATA static const bsls::Types::Uint64 k_MAX_US_FROM_EPOCH; static const bsls::Types::Uint64 k_REP_MASK = 0x8000000000000000ULL; static const bsls::Types::Uint64 k_DATE_MASK = 0xffffffe000000000ULL; static const bsls::Types::Uint64 k_TIME_MASK = 0x0000001fffffffffULL; static bsls::AtomicInt64 s_invalidRepresentationCount; // DATA bsls::Types::Uint64 d_value; // encoded offset from the epoch // FRIENDS friend DatetimeInterval operator-(const Datetime&, const Datetime&); friend bool operator==(const Datetime&, const Datetime&); friend bool operator!=(const Datetime&, const Datetime&); friend bool operator< (const Datetime&, const Datetime&); friend bool operator<=(const Datetime&, const Datetime&); friend bool operator> (const Datetime&, const Datetime&); friend bool operator>=(const Datetime&, const Datetime&); template <class HASHALG> friend void hashAppend(HASHALG& hashAlg, const Datetime&); // PRIVATE MANIPULATOR void setMicrosecondsFromEpoch(bsls::Types::Uint64 totalMicroseconds); // Assign to 'd_value' the representation of a datetime such that the // difference between this datetime and the epoch is the specified // 'totalMicroseconds'. // PRIVATE ACCESSORS bsls::Types::Uint64 microsecondsFromEpoch() const; // Return the difference, measured in microseconds, between this // datetime value, with 24:00:00.000000 converted to 0:00:00.000000, // and the epoch. bsls::Types::Uint64 updatedRepresentation() const; // If 'd_value' is a valid representation, return 'd_value'. // Otherwise, return the representation of the datetime corresponding // to the datetime implied by assuming the value in 'd_value' is the // concatenation of a 'Date' and a 'Time', and log or assert the // detection of an invalid date. bool validateAndTraceLogRepresentation() const; // Return 'true' if the representation is valid. Invoke a review // failure notifying of an invalid use of a 'bdlt::Datetime' instance // and return 'false' if the representation is invalid and // 'BSLS_ASSERT_SAFE' is inactive. The behavior is undefined if the // representation is invalid and 'BSLS_ASSERT_SAFE' is active. public: // CLASS METHODS static bool isValid(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); // Return 'true' if the specified 'year', 'month', and 'day' attribute // values, and the optionally specified 'hour', 'minute', 'second', // 'millisecond', and 'microsecond' attribute values, represent a valid // 'Datetime' value, and 'false' otherwise. Unspecified trailing // optional parameters default to 0. 'year', 'month', 'day', 'hour', // 'minute', 'second', 'millisecond', and 'microsecond' attribute // values represent a valid 'Datetime' value if // 'true == Date::isValidYearMonthDay(year, month, day)', // '0 <= hour < 24', '0 <= minute < 60', '0 <= second < 60', // '0 <= millisecond < 1000', and '0 <= microsecond < 1000'. // Additionally, a valid 'year', 'month', 'day' with the time portion // equal to 24:00:00.000000 also represents a valid 'Datetime' value. // 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 Datetime(); // Create a 'Datetime' object whose "date" and "time" parts have their // respective default-constructed values, "0001/01/01" and // "24:00:00.000000". Datetime(const Date& date); // IMPLICIT // Create a 'Datetime' object whose "date" part has the value of the // specified 'date' and whose "time" part has the value // "00:00:00.000000". Datetime(const Date& date, const Time& time); // Create a 'Datetime' object whose "date" and "time" parts have the // values of the specified 'date' and 'time', respectively. Datetime(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); // Create a 'Datetime' object whose "date" part has the value // represented by the specified 'year', 'month', and 'day' attributes, // and whose "time" part has the value represented by the optionally // specified 'hour', 'minute', 'second', 'millisecond', and // 'microsecond' attributes. Unspecified trailing optional parameters // default to 0. The behavior is undefined unless the eight attributes // (collectively) represent a valid 'Datetime' value (see 'isValid'). Datetime(const Datetime& original); // Create a 'Datetime' object having the value of the specified // 'original' object. //! ~Datetime() = default; // Destroy this 'Datetime' object. // MANIPULATORS Datetime& operator=(const Datetime& rhs); // Assign to this object the value of the specified 'rhs' object, and // return a reference providing modifiable access to this object. Datetime& operator+=(const bsls::TimeInterval& rhs); // Add to this object the value of the specified 'rhs' object, and // return a reference providing modifiable access to this object. If // '24 == hour()' on entry, set the 'hour' attribute of this object to // 0 before performing the addition. The behavior is undefined unless // the resulting value is valid for 'Datetime' (see 'isValid'). Datetime& operator-=(const bsls::TimeInterval& rhs); // Subtract from this object the value of the specified 'rhs' object, // and return a reference providing modifiable access to this object. // If '24 == hour()' on entry, set the 'hour' attribute of this object // to 0 before performing the subtraction. The behavior is undefined // unless the resulting value is valid for 'Datetime' (see 'isValid'). Datetime& operator+=(const DatetimeInterval& rhs); // Add to this object the value of the specified 'rhs' object, and // return a reference providing modifiable access to this object. If // '24 == hour()' on entry, set the 'hour' attribute of this object to // 0 before performing the addition. The behavior is undefined unless // the resulting value is valid for 'Datetime' (see 'isValid'). Datetime& operator-=(const DatetimeInterval& rhs); // Subtract from this object the value of the specified 'rhs' object, // and return a reference providing modifiable access to this object. // If '24 == hour()' on entry, set the 'hour' attribute of this object // to 0 before performing the subtraction. The behavior is undefined // unless the resulting value is valid for 'Datetime' (see 'isValid'). void setDatetime(const Date& date, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); // Set the value of this object to a 'Datetime' whose "date" part has // the value represented by the specified 'date', and whose "time" part // has the value represented by the optionally specified 'hour', // 'minute', 'second', 'millisecond', and 'microsecond' attributes. // Unspecified trailing optional parameters default to 0. The behavior // is undefined unless the attributes (collectively) represent a valid // 'Datetime' value (see 'isValid'). void setDatetime(const Date& date, const Time& time); // Set the value of this object to a 'Datetime' whose "date" part has // the value represented by the specified 'date', and whose "time" part // has the value represented by the specified 'time'. void setDatetime(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); // Set the value of this object to a 'Datetime' whose "date" part has // the value represented by the specified 'year', 'month', and 'day' // attributes, and whose "time" part has the value represented by the // optionally specified 'hour', 'minute', 'second', 'millisecond', and // 'microsecond' attributes. Unspecified trailing optional parameters // default to 0. The behavior is undefined unless the eight attributes // (collectively) represent a valid 'Datetime' value (see 'isValid'). int setDatetimeIfValid(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); // Set the "date" part of this object to have the value represented by // the specified 'year', 'month', and 'day' attributes, and set the // "time" part to have the value represented by the optionally // specified 'hour', 'minute', 'second', 'millisecond', and // 'microsecond' attributes, if the eight attribute values // (collectively) represent a valid 'Datetime' value (see 'isValid'). // Unspecified trailing optional parameters default to 0. Return 0 on // success, and a non-zero value (with no effect) otherwise. int setDatetimeIfValid(const Date& date, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); // Set the value of this object to a 'Datetime' whose "date" part has // the value represented by the specified 'date', and whose "time" part // has the value represented by the optionally specified 'hour', // 'minute', 'second', 'millisecond', and 'microsecond' attributes, if // the attribute values (collectively) represent a valid 'Datetime' // value (see 'isValid'). Unspecified trailing optional parameters // default to 0. Return 0 on success, and a non-zero value (with no // effect) otherwise. void setDate(const Date& date); // Set the "date" part of this object to have the value of the // specified 'date'. Note that this method has no effect on the "time" // part of this object. void setYearDay(int year, int dayOfYear); // Set the "date" part of this object to have the value represented by // the specified 'year' and 'dayOfYear' attribute values. The behavior // is undefined unless 'year' and 'dayOfYear' represent a valid 'Date' // value (i.e., 'true == Date::isValidYearDay(year, dayOfYear)'). Note // that this method has no effect on the "time" part of this object. int setYearDayIfValid(int year, int dayOfYear); // Set this object to have the value represented by the specified // 'year' and 'dayOfYear' if they comprise a valid 'Date' value (see // 'Date::isValidYearDay'). Return 0 on success, and a non-zero value // (with no effect) otherwise. void setYearMonthDay(int year, int month, int day); // Set the "date" part of this object to have the value represented by // the specified 'year', 'month', and 'day' attribute values. The // behavior is undefined unless 'year', 'month', and 'day' represent a // valid 'Date' value (i.e., // 'true == Date::isValidYearMonthDay(year, month, day)'). Note that // this method has no effect on the "time" part of this object. int setYearMonthDayIfValid(int year, int month, int day); // Set this object to have the value represented by the specified // 'year', 'month', and 'day' if they comprise a valid 'Date' value // (see 'Date::isValidYearMonthDay'). Return 0 on success, and a // non-zero value (with no effect) otherwise. void setTime(const Time& time); // Set the "time" part of this object to have the value of the // specified 'time'. Note that this method has no effect on the "date" // part of this object. void setTime(int hour, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); // Set the "time" part of this object to have the value represented by // the specified 'hour' attribute value and the optionally specified // 'minute', 'second', 'millisecond', and 'microsecond' attribute // values. Unspecified trailing optional parameters default to 0. The // behavior is undefined unless 'hour', 'minute', 'second', // 'millisecond', and 'microsecond' represent a valid "time" portion of // a 'Datetime' value. Note that this method has no effect on the // "date" part of this object. int setTimeIfValid(int hour, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); // Set the "time" part of this object to have the value represented by // the specified 'hour' attribute value and the optionally specified // 'minute', 'second', 'millisecond', and 'microsecond' attribute // values if they comprise a valid "time" portion of a 'DateTime' // value. Unspecified trailing optional parameters default to 0. // Return 0 on success, and a non-zero value (with no effect) // otherwise. Note that this method has no effect on the "date" part // of this object. void setHour(int hour); // Set the "hour" attribute of this object to the specified 'hour' // value. If '24 == hour', set the 'minute', 'second', 'millisecond', // and 'microsecond' attributes to 0. The behavior is undefined // unless '0 <= hour <= 24'. Note that this method has no effect on // the "date" part of this object. int setHourIfValid(int hour); // Set the "hour" attribute of this object to the specified 'hour' // value if '0 <= hour <= 24'. If '24 == hour', set the 'minute', // 'second', 'millisecond', and 'microsecond' attributes to 0. Return // 0 on success, and a non-zero value (with no effect) otherwise. Note // that this method has no effect on the "date" part of this object. void setMinute(int minute); // Set the "minute" attribute of this object to the specified 'minute' // value. If '24 == hour()', set the 'hour' attribute to 0. The // behavior is undefined unless '0 <= minute <= 59'. Note that this // method has no effect on the "date" part of this object. int setMinuteIfValid(int minute); // Set the "minute" attribute of this object to the specified 'minute' // value if '0 <= minute <= 59'. If '24 == hour()', set the 'hour' // attribute to 0. Return 0 on success, and a non-zero value (with no // effect) otherwise. Note that this method has no effect on the // "date" part of this object. void setSecond(int second); // Set the "second" attribute of this object to the specified 'second' // value. If '24 == hour()', set the 'hour' attribute to 0. The // behavior is undefined unless '0 <= second <= 59'. Note that this // method has no effect on the "date" part of this object. int setSecondIfValid(int second); // Set the "second" attribute of this object to the specified 'second' // value if '0 <= second <= 59'. If '24 == hour()', set the 'hour' // attribute to 0. Return 0 on success, and a non-zero value (with no // effect) otherwise. Note that this method has no effect on the // "date" part of this object. void setMillisecond(int millisecond); // Set the "millisecond" attribute of this object to the specified // 'millisecond' value. If '24 == hour()', set the 'hour' attribute to // 0. The behavior is undefined unless '0 <= millisecond <= 999'. // Note that this method has no effect on the "date" part of this // object. int setMillisecondIfValid(int millisecond); // Set the "millisecond" attribute of this object to the specified // 'millisecond' value if '0 <= millisecond <= 999'. If // '24 == hour()', set the 'hour' attribute to 0. Return 0 on success, // and a non-zero value (with no effect) otherwise. Note that this // method has no effect on the "date" part of this object. void setMicrosecond(int microsecond); // Set the "microsecond" attribute of this object to the specified // 'microsecond' value. If '24 == hour()', set the 'hour' attribute to // 0. The behavior is undefined unless '0 <= microsecond <= 999'. // Note that this method has no effect on the "date" part of this // object. int setMicrosecondIfValid(int microsecond); // Set the "microsecond" attribute of this object to the specified // 'microsecond' value if '0 <= microsecond <= 999'. If // '24 == hour()', set the 'hour' attribute to 0. Return 0 on success, // and a non-zero value (with no effect) otherwise. Note that this // method has no effect on the "date" part of this object. Datetime& addDays(int days); // Add the specified number of 'days' to the value of this object. // Return a reference providing modifiable access to this object. The // behavior is undefined unless the resulting value is in the valid // range for a 'Datetime' object. Note that this method has no effect // on the "time" part of this object. Also note that 'days' may be // positive, 0, or negative. int addDaysIfValid(int days); // Add the specified number of 'days' to the value of this object, if // the resulting value is in the valid range for a 'Datetime' object. // Return 0 on success, and a non-zero value (with no effect) // otherwise. Note that this method has no effect on the "time" part // of this object. Also note that 'days' may be positive, 0, or // negative. Datetime& addTime(bsls::Types::Int64 hours, bsls::Types::Int64 minutes = 0, bsls::Types::Int64 seconds = 0, bsls::Types::Int64 milliseconds = 0, bsls::Types::Int64 microseconds = 0); // Add the specified number of 'hours', and the optionally specified // number of 'minutes', 'seconds', 'milliseconds', and 'microseconds' // to the value of this object, adjusting the "date" part of this // object accordingly. Unspecified trailing optional parameters // default to 0. Return a reference providing modifiable access to // this object. If '24 == hour()' on entry, set the 'hour' attribute // to 0 before performing the addition. The behavior is undefined // unless the resulting value is in the valid range for a 'Datetime' // object. Note that each argument independently may be positive, // negative, or 0. int addTimeIfValid(bsls::Types::Int64 hours, bsls::Types::Int64 minutes = 0, bsls::Types::Int64 seconds = 0, bsls::Types::Int64 milliseconds = 0, bsls::Types::Int64 microseconds = 0); // Add the specified number of 'hours', and the optionally specified // number of 'minutes', 'seconds', 'milliseconds', and 'microseconds' // to the value of this object, adjusting the "date" part of this // object accordingly, if the resulting value is in the valid range for // a 'Datetime' object. Unspecified trailing optional parameters // default to 0. If '24 == hour()' on entry, set the 'hour' attribute // to 0 before performing the addition. Return 0 on success, and a // non-zero value (with no effect) otherwise. Note that each argument // independently may be positive, negative, or 0. Datetime& addHours(bsls::Types::Int64 hours); // Add the specified number of 'hours' to the value of this object, // adjusting the "date" part of the object accordingly. Return a // reference providing modifiable access to this object. If // '24 == hour()' on entry, set the 'hour' attribute to 0 before // performing the addition. The behavior is undefined unless the // resulting value is in the valid range for a 'Datetime' object. Note // that 'hours' may be positive, negative, or 0. int addHoursIfValid(bsls::Types::Int64 hours); // Add the specified number of 'hours' to the value of this object, // adjusting the "date" part of the object accordingly, if the // resulting value is in the valid range for a 'Datetime' object. If // '24 == hour()' on entry, set the 'hour' attribute to 0 before // performing the addition. Return 0 on success, and a non-zero value // (with no effect) otherwise. Note that 'hours' may be positive, // negative, or 0. Datetime& addMinutes(bsls::Types::Int64 minutes); // Add the specified number of 'minutes' to the value of this object, // adjusting the "date" part of the object accordingly. Return a // reference providing modifiable access to this object. If // '24 == hour()' on entry, set the 'hour' attribute to 0 before // performing the addition. The behavior is undefined unless the // resulting value is in the valid range for a 'Datetime' object. Note // that 'minutes' may be positive, negative, or 0. int addMinutesIfValid(bsls::Types::Int64 minutes); // Add the specified number of 'minutes' to the value of this object, // adjusting the "date" part of the object accordingly, if the // resulting value is in the valid range for a 'Datetime' object. If // '24 == hour()' on entry, set the 'hour' attribute to 0 before // performing the addition. Return 0 on success, and a non-zero value // (with no effect) otherwise. Note that 'minutes' may be positive, // negative, or 0. Datetime& addSeconds(bsls::Types::Int64 seconds); // Add the specified number of 'seconds' to the value of this object, // adjusting the "date" part of the object accordingly. Return a // reference providing modifiable access to this object. If // '24 == hour()' on entry, set the 'hour' attribute to 0 before // performing the addition. The behavior is undefined unless the // resulting value is in the valid range for a 'Datetime' object. Note // that 'seconds' may be positive, negative, or 0. int addSecondsIfValid(bsls::Types::Int64 seconds); // Add the specified number of 'seconds' to the value of this object, // adjusting the "date" part of the object accordingly, if the // resulting value is in the valid range for a 'Datetime' object. If // '24 == hour()' on entry, set the 'hour' attribute to 0 before // performing the addition. Return 0 on success, and a non-zero value // (with no effect) otherwise. Note that 'seconds' may be positive, // negative, or 0. Datetime& addMilliseconds(bsls::Types::Int64 milliseconds); // Add the specified number of 'milliseconds' to the value of this // object, adjusting the "date" part of the object accordingly. Return // a reference providing modifiable access to this object. If // '24 == hour()' on entry, set the 'hour' attribute to 0 before // performing the addition. The behavior is undefined unless the // resulting value is in the valid range for a 'Datetime' object. Note // that 'milliseconds' may be positive, negative, or 0. int addMillisecondsIfValid(bsls::Types::Int64 milliseconds); // Add the specified number of 'milliseconds' to the value of this // object, adjusting the "date" part of the object accordingly, if the // resulting value is in the valid range for a 'Datetime' object. If // '24 == hour()' on entry, set the 'hour' attribute to 0 before // performing the addition. Return 0 on success, and a non-zero value // (with no effect) otherwise. Note that 'milliseconds' may be // positive, negative, or 0. Datetime& addMicroseconds(bsls::Types::Int64 microseconds); // Add the specified number of 'microseconds' to the value of this // object, adjusting the "date" part of the object accordingly. Return // a reference providing modifiable access to this object. If // '24 == hour()' on entry, set the 'hour' attribute to 0 before // performing the addition. The behavior is undefined unless the // resulting value is in the valid range for a 'Datetime' object. Note // that 'microseconds' may be positive, negative, or 0. int addMicrosecondsIfValid(bsls::Types::Int64 microseconds); // Add the specified number of 'microseconds' to the value of this // object, adjusting the "date" part of the object accordingly, if the // resulting value is in the valid range for a 'Datetime' object. If // '24 == hour()' on entry, set the 'hour' attribute to 0 before // performing the addition. Return 0 on success, and a non-zero value // (with no effect) otherwise. Note that 'microseconds' may be // positive, negative, or 0. // 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 Date date() const; // Return the value of the "date" part of this object. int day() const; // Return the value of the 'day' (of the month) attribute of this // object. DayOfWeek::Enum dayOfWeek() const; // Return the value of the 'dayOfWeek' attribute associated with the // 'day' (of the month) attribute of this object. int dayOfYear() const; // Return the value of the 'dayOfYear' attribute of this object. void getTime(int *hour, int *minute = 0, int *second = 0, int *millisecond = 0, int *microsecond = 0) const; // Load, into the specified 'hour', and the optionally specified // 'minute', 'second', 'millisecond', and 'microsecond' the respective // 'hour', 'minute', 'second', 'millisecond', and 'microsecond' // attribute values from this time object. Unspecified arguments // default to 0. Supplying 0 for an address argument suppresses the // loading of the value for the corresponding attribute, but has no // effect on the loading of other attribute values. int hour() const; // Return the value of the 'hour' attribute of this object. int microsecond() const; // Return the value of the 'microsecond' attribute of this object. int millisecond() const; // Return the value of the 'millisecond' attribute of this object. int minute() const; // Return the value of the 'minute' attribute of this object. int month() const; // Return the value of the 'month' attribute of this object. int second() const; // Return the value of the 'second' attribute of this object. Time time() const; // Return the value of the "time" part of this object. int year() const; // Return the value of the 'year' attribute of this object. 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. // 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 this // human-readable format is not fully specified, and can change without // notice. #ifndef BDE_OPENSOURCE_PUBLICATION // pending deprecation 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 'print' instead. // // Format this datetime to the specified output 'stream' and return a // reference to the modifiable 'stream'. int validateAndSetDatetime(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0); // !DEPRECATED!: Use 'setDatetimeIfValid' instead. // // Set the "date" part of this object's value to the specified 'year', // 'month', and 'day', and the "time" part to the optionally specified // 'hour', 'minute', 'second', and 'millisecond', if they represent a // valid 'Datetime' value, with trailing fields that are not specified // set to 0. Return 0 on success, and a non-zero value (with no // effect) otherwise. #endif // BDE_OMIT_INTERNAL_DEPRECATED -- BDE2.22 }; // FREE OPERATORS Datetime operator+(const Datetime& lhs, const bsls::TimeInterval& rhs); // Return a 'Datetime' object having a value that is the sum of the // specified 'lhs' ('Datetime') and the specified 'rhs' // ('bsls::TimeInterval'). If '24 == lhs.hour()', the result is the same // as if the 'hour' attribute of 'lhs' is 0. The behavior is undefined // unless the resulting value is in the valid range for a 'Datetime' // object. Datetime operator+(const bsls::TimeInterval& lhs, const Datetime& rhs); // Return a 'Datetime' object having a value that is the sum of the // specified 'lhs' ('bsls::TimeInterval') and the specified 'rhs' // ('Datetime'). If '24 == rhs.hour()', the result is the same as if the // 'hour' attribute of 'rhs' is 0. The behavior is undefined unless the // resulting value is in the valid range for a 'Datetime' object. Datetime operator+(const Datetime& lhs, const DatetimeInterval& rhs); // Return a 'Datetime' object having a value that is the sum of the // specified 'lhs' ('Datetime') and the specified 'rhs' // ('DatetimeInterval'). If '24 == lhs.hour()', the result is the same as // if the 'hour' attribute of 'lhs' is 0. The behavior is undefined unless // the resulting value is in the valid range for a 'Datetime' object. Datetime operator+(const DatetimeInterval& lhs, const Datetime& rhs); // Return a 'Datetime' object having a value that is the sum of the // specified 'lhs' ('DatetimeInterval') and the specified 'rhs' // ('Datetime'). If '24 == rhs.hour()', the result is the same as if the // 'hour' attribute of 'rhs' is 0. The behavior is undefined unless the // resulting value is in the valid range for a 'Datetime' object. Datetime operator-(const Datetime& lhs, const bsls::TimeInterval& rhs); // Return a 'Datetime' object having a value that is the difference between // the specified 'lhs' ('Datetime') and the specified 'rhs' // ('bsls::TimeInterval'). If '24 == lhs.hour()', the result is the same // as if the 'hour' attribute of 'lhs' is 0. The behavior is undefined // unless the resulting value is in the valid range for a 'Datetime' // object. Datetime operator-(const Datetime& lhs, const DatetimeInterval& rhs); // Return a 'Datetime' object having a value that is the difference between // the specified 'lhs' ('Datetime') and the specified 'rhs' // ('DatetimeInterval'). If '24 == lhs.hour()', the result is the same as // if the 'hour' attribute of 'lhs' is 0. The behavior is undefined unless // the resulting value is in the valid range for a 'Datetime' object. DatetimeInterval operator-(const Datetime& lhs, const Datetime& rhs); // Return a 'DatetimeInterval' object having a value that is the difference // between the specified 'lhs' ('Datetime') and the specified 'rhs' // ('Datetime'). If the 'hour' attribute of either operand is 24, the // result is the same as if that 'hour' attribute is 0. The behavior is // undefined unless the resulting value is in the valid range for a // 'DatetimeInterval' object. bool operator==(const Datetime& lhs, const Datetime& rhs); // Return 'true' if the specified 'lhs' and 'rhs' objects have the same // value, and 'false' otherwise. Two 'Datetime' objects have the same // value if they have the same values for their "date" and "time" parts, // respectively. bool operator!=(const Datetime& lhs, const Datetime& rhs); // Return 'true' if the specified 'lhs' and 'rhs' 'Datetime' objects do not // have the same value, and 'false' otherwise. Two 'Datetime' objects do // not have the same value if they do not have the same values for either // of their "date" or "time" parts, respectively. bool operator<(const Datetime& lhs, const Datetime& rhs); // Return 'true' if the value of the specified 'lhs' object is less than // the value of the specified 'rhs' object, and 'false' otherwise. A // 'Datetime' object 'a' is less than a 'Datetime' object 'b' if // 'a.date() < b.date()', or if 'a.date() == b.date()' and the time portion // of 'a' is less than the time portion of 'b'. The behavior is undefined // unless '24 != lhs.hour() && 24 != rhs.hour()'. bool operator<=(const Datetime& lhs, const Datetime& rhs); // Return 'true' if the value of the specified 'lhs' object is less than or // equal to the value of the specified 'rhs' object, and 'false' otherwise. // The behavior is undefined unless '24 != lhs.hour() && 24 != rhs.hour()'. bool operator>(const Datetime& lhs, const Datetime& rhs); // Return 'true' if the value of the specified 'lhs' object is greater than // the value of the specified 'rhs' object, and 'false' otherwise. A // 'Datetime' object 'a' is greater than a 'Datetime' object 'b' if // 'a.date() > b.date()', or if 'a.date() == b.date()' and the time portion // of 'a' is greater than the time portion of 'b'. The behavior is // undefined unless '24 != lhs.hour() && 24 != rhs.hour()'. bool operator>=(const Datetime& lhs, const Datetime& rhs); // Return 'true' if the value of the specified 'lhs' object is greater than // or equal to the value of the specified 'rhs' object, and 'false' // otherwise. The behavior is undefined unless // '24 != lhs.hour() && 24 != rhs.hour()'. bsl::ostream& operator<<(bsl::ostream& stream, const Datetime& object); // Write the value of the specified 'object' object to the specified output // 'stream' in a single-line format, and return a reference to 'stream'. // If 'stream' is not valid on entry, this operation has no effect. Note // that this human-readable format is not fully specified, can change // without notice, and is logically equivalent to: //.. // print(stream, 0, -1); //.. // FREE FUNCTIONS template <class HASHALG> void hashAppend(HASHALG& hashAlg, const Datetime& 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 'Datetime'. // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // -------------- // class Datetime // -------------- // PRIVATE MANIPULATOR inline void Datetime::setMicrosecondsFromEpoch(bsls::Types::Uint64 totalMicroseconds) { d_value = ((totalMicroseconds / TimeUnitRatio::k_US_PER_D) << k_NUM_TIME_BITS) + totalMicroseconds % TimeUnitRatio::k_US_PER_D; d_value |= k_REP_MASK; } // PRIVATE ACCESSORS inline bsls::Types::Uint64 Datetime::microsecondsFromEpoch() const { if (validateAndTraceLogRepresentation()) { int h = hour(); bsls::Types::Uint64 value = d_value & (~k_REP_MASK); if (TimeUnitRatio::k_H_PER_D_32 != h) { return (value >> k_NUM_TIME_BITS) * TimeUnitRatio::k_US_PER_D + (value & k_TIME_MASK); // RETURN } return (value >> k_NUM_TIME_BITS) * TimeUnitRatio::k_US_PER_D; // RETURN } #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bsls::Types::Uint64 days = (d_value & 0xffffffff) - 1; bsls::Types::Uint64 milliseconds = (d_value >> 32) % TimeUnitRatio::k_MS_PER_D_32; #else bsls::Types::Uint64 days = (d_value >> 32) - 1; bsls::Types::Uint64 milliseconds = (d_value & 0xffffffff) % TimeUnitRatio::k_MS_PER_D_32; #endif return TimeUnitRatio::k_US_PER_D * days + TimeUnitRatio::k_US_PER_MS * milliseconds; } inline bsls::Types::Uint64 Datetime::updatedRepresentation() const { if (validateAndTraceLogRepresentation()) { return d_value; // RETURN } #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bsls::Types::Uint64 days = (d_value & 0xffffffff) - 1; bsls::Types::Uint64 milliseconds = d_value >> 32; #else bsls::Types::Uint64 days = (d_value >> 32) - 1; bsls::Types::Uint64 milliseconds = d_value & 0xffffffff; #endif return (days << k_NUM_TIME_BITS) | (TimeUnitRatio::k_US_PER_MS * milliseconds) | k_REP_MASK; } inline bool Datetime::validateAndTraceLogRepresentation() const { if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(k_REP_MASK <= d_value)) { return true; // RETURN } BSLS_ASSERT_SAFE( 0 && "detected invalid 'bdlt::Datetime'; see TEAM 579660115"); BSLS_REVIEW_INVOKE( "detected invalid 'bdlt::Datetime'; see TEAM 579660115"); return false; } // CLASS METHODS inline bool Datetime::isValid(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond) { return Date::isValidYearMonthDay(year, month, day) && ( (0 <= hour && hour < bdlt::TimeUnitRatio::k_H_PER_D_32 && 0 <= minute && minute < bdlt::TimeUnitRatio::k_M_PER_H_32 && 0 <= second && second < bdlt::TimeUnitRatio::k_S_PER_M_32 && 0 <= millisecond && millisecond < bdlt::TimeUnitRatio::k_MS_PER_S_32 && 0 <= microsecond && microsecond < bdlt::TimeUnitRatio::k_US_PER_MS_32) || (bdlt::TimeUnitRatio::k_H_PER_D_32 == hour && 0 == minute && 0 == second && 0 == millisecond && 0 == microsecond)); } // Aspects inline int Datetime::maxSupportedBdexVersion(int versionSelector) { if (versionSelector >= 20160411) { return 2; // RETURN } return 1; } // CREATORS inline Datetime::Datetime() : d_value(TimeUnitRatio::k_US_PER_D) { d_value |= k_REP_MASK; } inline Datetime::Datetime(const Date& date) : d_value(static_cast<bsls::Types::Uint64>(date - Date()) << k_NUM_TIME_BITS) { d_value |= k_REP_MASK; } inline Datetime::Datetime(const Date& date, const Time& time) { setDatetime(date, time); } inline Datetime::Datetime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond) { setDatetime(year, month, day, hour, minute, second, millisecond, microsecond); } inline Datetime::Datetime(const Datetime& original) : d_value(original.d_value) { d_value = updatedRepresentation(); } // MANIPULATORS inline Datetime& Datetime::operator=(const Datetime& rhs) { d_value = rhs.d_value; d_value = updatedRepresentation(); return *this; } inline Datetime& Datetime::operator+=(const bsls::TimeInterval& rhs) { BSLS_ASSERT_SAFE( rhs.totalMicroseconds() <= static_cast<bsls::Types::Int64>( k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())); BSLS_ASSERT_SAFE(-rhs.totalMicroseconds() <= static_cast<bsls::Types::Int64>( microsecondsFromEpoch())); bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch() + rhs.totalMicroseconds(); setMicrosecondsFromEpoch(totalMicroseconds); return *this; } inline Datetime& Datetime::operator-=(const bsls::TimeInterval& rhs) { BSLS_ASSERT_SAFE(-rhs.totalMicroseconds() <= static_cast<bsls::Types::Int64>( k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())); BSLS_ASSERT_SAFE( rhs.totalMicroseconds() <= static_cast<bsls::Types::Int64>( microsecondsFromEpoch())); bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch() - rhs.totalMicroseconds(); setMicrosecondsFromEpoch(totalMicroseconds); return *this; } inline Datetime& Datetime::operator+=(const DatetimeInterval& rhs) { BSLS_ASSERT_SAFE( rhs.totalMicroseconds() <= static_cast<bsls::Types::Int64>( k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())); BSLS_ASSERT_SAFE(-rhs.totalMicroseconds() <= static_cast<bsls::Types::Int64>( microsecondsFromEpoch())); bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch() + rhs.totalMicroseconds(); setMicrosecondsFromEpoch(totalMicroseconds); return *this; } inline Datetime& Datetime::operator-=(const DatetimeInterval& rhs) { BSLS_ASSERT_SAFE(-rhs.totalMicroseconds() <= static_cast<bsls::Types::Int64>( k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())); BSLS_ASSERT_SAFE( rhs.totalMicroseconds() <= static_cast<bsls::Types::Int64>( microsecondsFromEpoch())); bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch() - rhs.totalMicroseconds(); setMicrosecondsFromEpoch(totalMicroseconds); return *this; } inline void Datetime::setDatetime(const Date& date, int hour, int minute, int second, int millisecond, int microsecond) { BSLS_ASSERT_SAFE(Datetime::isValid(date.year(), date.month(), date.day(), hour, minute, second, millisecond, microsecond)); d_value = (static_cast<bsls::Types::Uint64>(date - Date()) << k_NUM_TIME_BITS) + TimeUnitRatio::k_US_PER_H * hour + TimeUnitRatio::k_US_PER_M * minute + TimeUnitRatio::k_US_PER_S * second + TimeUnitRatio::k_US_PER_MS * millisecond + microsecond; d_value |= k_REP_MASK; } inline void Datetime::setDatetime(const Date& date, const Time& time) { if (24 != time.hour()) { d_value = (static_cast<bsls::Types::Uint64>(date - Date()) << k_NUM_TIME_BITS) + (time - Time(0)).totalMicroseconds(); } else { d_value = (static_cast<bsls::Types::Uint64>(date - Date()) << k_NUM_TIME_BITS) + TimeUnitRatio::k_US_PER_D; } d_value |= k_REP_MASK; } inline void Datetime::setDatetime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond) { BSLS_ASSERT_SAFE(Datetime::isValid(year, month, day, hour, minute, second, millisecond, microsecond)); setDatetime(Date(year, month, day), hour, minute, second, millisecond, microsecond); } inline int Datetime::setDatetimeIfValid(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if (Datetime::isValid(year, month, day, hour, minute, second, millisecond, microsecond)) { setDatetime(Date(year, month, day), hour, minute, second, millisecond, microsecond); return k_SUCCESS; // RETURN } return k_FAILURE; } inline int Datetime::setDatetimeIfValid(const Date& date, int hour, int minute, int second, int millisecond, int microsecond) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if (Datetime::isValid(date.year(), date.month(), date.day(), hour, minute, second, millisecond, microsecond)) { setDatetime(date, hour, minute, second, millisecond, microsecond); return k_SUCCESS; // RETURN } return k_FAILURE; } inline void Datetime::setDate(const Date& date) { d_value = updatedRepresentation(); d_value = (static_cast<bsls::Types::Uint64>(date - Date()) << k_NUM_TIME_BITS) | (d_value & k_TIME_MASK); d_value |= k_REP_MASK; } inline void Datetime::setYearDay(int year, int dayOfYear) { BSLS_ASSERT_SAFE(Date::isValidYearDay(year, dayOfYear)); setDate(Date(year, dayOfYear)); } inline int Datetime::setYearDayIfValid(int year, int dayOfYear) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if (Date::isValidYearDay(year, dayOfYear)) { setDate(Date(year, dayOfYear)); return k_SUCCESS; // RETURN } return k_FAILURE; } inline void Datetime::setYearMonthDay(int year, int month, int day) { BSLS_PRECONDITIONS_BEGIN(); BSLS_ASSERT_SAFE(Date::isValidYearMonthDay(year, month, day)); BSLS_PRECONDITIONS_END(); setDate(Date(year, month, day)); } inline int Datetime::setYearMonthDayIfValid(int year, int month, int day) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if (Date::isValidYearMonthDay(year, month, day)) { setDate(Date(year, month, day)); return k_SUCCESS; // RETURN } return k_FAILURE; } inline void Datetime::setTime(const Time& time) { d_value = updatedRepresentation(); if (24 != time.hour()) { d_value = (d_value & k_DATE_MASK) | (time - Time(0)).totalMicroseconds(); } else { d_value = (d_value & k_DATE_MASK) | TimeUnitRatio::k_US_PER_D; } } inline void Datetime::setTime(int hour, int minute, int second, int millisecond, int microsecond) { BSLS_PRECONDITIONS_BEGIN(); BSLS_ASSERT_SAFE( (0 <= hour && hour < bdlt::TimeUnitRatio::k_H_PER_D_32 && 0 <= minute && minute < bdlt::TimeUnitRatio::k_M_PER_H_32 && 0 <= second && second < bdlt::TimeUnitRatio::k_S_PER_M_32 && 0 <= millisecond && millisecond < bdlt::TimeUnitRatio::k_MS_PER_S_32 && 0 <= microsecond && microsecond < bdlt::TimeUnitRatio::k_US_PER_MS_32) || (bdlt::TimeUnitRatio::k_H_PER_D_32 == hour && 0 == minute && 0 == second && 0 == millisecond && 0 == microsecond)); BSLS_PRECONDITIONS_END(); d_value = updatedRepresentation(); d_value = TimeUnitRatio::k_US_PER_H * hour + TimeUnitRatio::k_US_PER_M * minute + TimeUnitRatio::k_US_PER_S * second + TimeUnitRatio::k_US_PER_MS * millisecond + microsecond + (d_value & k_DATE_MASK); } inline int Datetime::setTimeIfValid(int hour, int minute, int second, int millisecond, int microsecond) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if ( (0 <= hour && hour < bdlt::TimeUnitRatio::k_H_PER_D_32 && 0 <= minute && minute < bdlt::TimeUnitRatio::k_M_PER_H_32 && 0 <= second && second < bdlt::TimeUnitRatio::k_S_PER_M_32 && 0 <= millisecond && millisecond < bdlt::TimeUnitRatio::k_MS_PER_S_32 && 0 <= microsecond && microsecond < bdlt::TimeUnitRatio::k_US_PER_MS_32) || (bdlt::TimeUnitRatio::k_H_PER_D_32 == hour && 0 == minute && 0 == second && 0 == millisecond && 0 == microsecond)) { setTime(hour, minute, second, millisecond, microsecond); return k_SUCCESS; // RETURN } return k_FAILURE; } inline void Datetime::setHour(int hour) { BSLS_ASSERT_SAFE(0 <= hour); BSLS_ASSERT_SAFE( hour <= 24); d_value = updatedRepresentation(); if (TimeUnitRatio::k_H_PER_D_32 != hour) { bsls::Types::Uint64 microseconds = d_value & k_TIME_MASK; microseconds = microseconds % TimeUnitRatio::k_US_PER_H + hour * TimeUnitRatio::k_US_PER_H; d_value = microseconds | (d_value & k_DATE_MASK); } else { d_value = TimeUnitRatio::k_US_PER_D | (d_value & k_DATE_MASK); } } inline int Datetime::setHourIfValid(int hour) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if (0 <= hour && hour <= 24) { setHour(hour); return k_SUCCESS; // RETURN } return k_FAILURE; } inline void Datetime::setMinute(int minute) { BSLS_ASSERT_SAFE(0 <= minute); BSLS_ASSERT_SAFE( minute <= 59); d_value = updatedRepresentation(); if (TimeUnitRatio::k_H_PER_D_32 != hour()) { bsls::Types::Uint64 microseconds = d_value & k_TIME_MASK; microseconds = microseconds / TimeUnitRatio::k_US_PER_H * TimeUnitRatio::k_US_PER_H + microseconds % TimeUnitRatio::k_US_PER_M + minute * TimeUnitRatio::k_US_PER_M; d_value = microseconds | (d_value & k_DATE_MASK); } else { d_value = TimeUnitRatio::k_US_PER_M * minute | (d_value & k_DATE_MASK); } } inline int Datetime::setMinuteIfValid(int minute) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if (0 <= minute && minute <= 59) { setMinute(minute); return k_SUCCESS; // RETURN } return k_FAILURE; } inline void Datetime::setSecond(int second) { BSLS_ASSERT_SAFE(0 <= second); BSLS_ASSERT_SAFE( second <= 59); d_value = updatedRepresentation(); if (TimeUnitRatio::k_H_PER_D_32 != hour()) { bsls::Types::Uint64 microseconds = d_value & k_TIME_MASK; microseconds = microseconds / TimeUnitRatio::k_US_PER_M * TimeUnitRatio::k_US_PER_M + microseconds % TimeUnitRatio::k_US_PER_S + second * TimeUnitRatio::k_US_PER_S; d_value = microseconds | (d_value & k_DATE_MASK); } else { d_value = TimeUnitRatio::k_US_PER_S * second | (d_value & k_DATE_MASK); } } inline int Datetime::setSecondIfValid(int second) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if (0 <= second && second <= 59) { setSecond(second); return k_SUCCESS; // RETURN } return k_FAILURE; } inline void Datetime::setMillisecond(int millisecond) { BSLS_ASSERT_SAFE(0 <= millisecond); BSLS_ASSERT_SAFE( millisecond <= 999); d_value = updatedRepresentation(); if (TimeUnitRatio::k_H_PER_D_32 != hour()) { bsls::Types::Uint64 microseconds = d_value & k_TIME_MASK; microseconds = microseconds / TimeUnitRatio::k_US_PER_S * TimeUnitRatio::k_US_PER_S + microseconds % TimeUnitRatio::k_US_PER_MS + millisecond * TimeUnitRatio::k_US_PER_MS; d_value = microseconds | (d_value & k_DATE_MASK); } else { d_value = TimeUnitRatio::k_US_PER_MS * millisecond | (d_value & k_DATE_MASK); } } inline int Datetime::setMillisecondIfValid(int millisecond) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if (0 <= millisecond && millisecond <= 999) { setMillisecond(millisecond); return k_SUCCESS; // RETURN } return k_FAILURE; } inline void Datetime::setMicrosecond(int microsecond) { BSLS_ASSERT_SAFE(0 <= microsecond); BSLS_ASSERT_SAFE( microsecond <= 999); d_value = updatedRepresentation(); if (TimeUnitRatio::k_H_PER_D_32 != hour()) { bsls::Types::Uint64 microseconds = d_value & k_TIME_MASK; microseconds = microseconds / TimeUnitRatio::k_US_PER_MS * TimeUnitRatio::k_US_PER_MS + microsecond; d_value = microseconds | (d_value & k_DATE_MASK); } else { d_value = (d_value & k_DATE_MASK) | microsecond; } } inline int Datetime::setMicrosecondIfValid(int microsecond) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if (0 <= microsecond && microsecond <= 999) { setMicrosecond(microsecond); return k_SUCCESS; // RETURN } return k_FAILURE; } inline Datetime& Datetime::addDays(int days) { BSLS_ASSERT_SAFE(0 == Date(date()).addDaysIfValid(days)); d_value = updatedRepresentation(); // needed to avoid double logging from // 'date' and then 'setDate' setDate(date() + days); return *this; } inline int Datetime::addDaysIfValid(int days) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if (0 == Date(date()).addDaysIfValid(days)) { addDays(days); return k_SUCCESS; // RETURN } return k_FAILURE; } inline Datetime& Datetime::addTime(bsls::Types::Int64 hours, bsls::Types::Int64 minutes, bsls::Types::Int64 seconds, bsls::Types::Int64 milliseconds, bsls::Types::Int64 microseconds) { // Reduce the input parameters to 'days' and 'microseconds', without any // constraints on the representation, without the possibility of overflow // or underflow. bsls::Types::Int64 days = hours / TimeUnitRatio::k_H_PER_D + minutes / TimeUnitRatio::k_M_PER_D + seconds / TimeUnitRatio::k_S_PER_D + milliseconds / TimeUnitRatio::k_MS_PER_D + microseconds / TimeUnitRatio::k_US_PER_D; hours %= TimeUnitRatio::k_H_PER_D; minutes %= TimeUnitRatio::k_M_PER_D; seconds %= TimeUnitRatio::k_S_PER_D; milliseconds %= TimeUnitRatio::k_MS_PER_D; microseconds %= TimeUnitRatio::k_US_PER_D; microseconds = hours * TimeUnitRatio::k_US_PER_H + minutes * TimeUnitRatio::k_US_PER_M + seconds * TimeUnitRatio::k_US_PER_S + milliseconds * TimeUnitRatio::k_US_PER_MS + microseconds; // Modify the representation to ensure 'days' and 'microseconds' have the // same sign (i.e., both are positive or both are negative or 'days == 0'). days += microseconds / TimeUnitRatio::k_US_PER_D; microseconds %= TimeUnitRatio::k_US_PER_D; if (days > 0 && microseconds < 0) { --days; microseconds += TimeUnitRatio::k_US_PER_D; } else if (days < 0 && microseconds > 0) { ++days; microseconds -= TimeUnitRatio::k_US_PER_D; } // Piecewise add the 'days' and 'microseconds' to this datetime. bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch(); BSLS_ASSERT_SAFE( days <= static_cast<bsls::Types::Int64> ((k_MAX_US_FROM_EPOCH - totalMicroseconds) / TimeUnitRatio::k_US_PER_D)); BSLS_ASSERT_SAFE(-days <= static_cast<bsls::Types::Int64> (totalMicroseconds / TimeUnitRatio::k_US_PER_D)); totalMicroseconds += days * TimeUnitRatio::k_US_PER_D; BSLS_ASSERT_SAFE( microseconds <= static_cast<bsls::Types::Int64> (k_MAX_US_FROM_EPOCH - totalMicroseconds)); BSLS_ASSERT_SAFE(-microseconds <= static_cast<bsls::Types::Int64> (totalMicroseconds)); totalMicroseconds += microseconds; // Assign the value. setMicrosecondsFromEpoch(totalMicroseconds); return *this; } inline int Datetime::addTimeIfValid(bsls::Types::Int64 hours, bsls::Types::Int64 minutes, bsls::Types::Int64 seconds, bsls::Types::Int64 milliseconds, bsls::Types::Int64 microseconds) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; // Reduce the input parameters to 'days' and 'microseconds', without any // constraints on the representation, without the possibility of overflow // or underflow. bsls::Types::Int64 days = hours / TimeUnitRatio::k_H_PER_D + minutes / TimeUnitRatio::k_M_PER_D + seconds / TimeUnitRatio::k_S_PER_D + milliseconds / TimeUnitRatio::k_MS_PER_D + microseconds / TimeUnitRatio::k_US_PER_D; hours %= TimeUnitRatio::k_H_PER_D; minutes %= TimeUnitRatio::k_M_PER_D; seconds %= TimeUnitRatio::k_S_PER_D; milliseconds %= TimeUnitRatio::k_MS_PER_D; microseconds %= TimeUnitRatio::k_US_PER_D; microseconds = hours * TimeUnitRatio::k_US_PER_H + minutes * TimeUnitRatio::k_US_PER_M + seconds * TimeUnitRatio::k_US_PER_S + milliseconds * TimeUnitRatio::k_US_PER_MS + microseconds; // Modify the representation to ensure 'days' and 'microseconds' have the // same sign (i.e., both are positive or both are negative or 'days == 0'). days += microseconds / TimeUnitRatio::k_US_PER_D; microseconds %= TimeUnitRatio::k_US_PER_D; if (days > 0 && microseconds < 0) { --days; microseconds += TimeUnitRatio::k_US_PER_D; } else if (days < 0 && microseconds > 0) { ++days; microseconds -= TimeUnitRatio::k_US_PER_D; } // Piecewise add the 'days' and 'microseconds' to this datetime. bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch(); if (!( days <= static_cast<bsls::Types::Int64> ((k_MAX_US_FROM_EPOCH - totalMicroseconds) / TimeUnitRatio::k_US_PER_D) && -days <= static_cast<bsls::Types::Int64> (totalMicroseconds / TimeUnitRatio::k_US_PER_D))) { return k_FAILURE; // RETURN } totalMicroseconds += days * TimeUnitRatio::k_US_PER_D; if (!( microseconds <= static_cast<bsls::Types::Int64> (k_MAX_US_FROM_EPOCH - totalMicroseconds) && -microseconds <= static_cast<bsls::Types::Int64> (totalMicroseconds))) { return k_FAILURE; // RETURN } totalMicroseconds += microseconds; // Assign the value. setMicrosecondsFromEpoch(totalMicroseconds); return k_SUCCESS; } inline Datetime& Datetime::addHours(bsls::Types::Int64 hours) { BSLS_ASSERT_SAFE( hours <= static_cast<bsls::Types::Int64> ((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch()) / TimeUnitRatio::k_US_PER_H)); BSLS_ASSERT_SAFE(-hours <= static_cast<bsls::Types::Int64> (microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_H)); bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch(); setMicrosecondsFromEpoch(hours * TimeUnitRatio::k_US_PER_H + totalMicroseconds); return *this; } inline int Datetime::addHoursIfValid(bsls::Types::Int64 hours) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if ( hours <= static_cast<bsls::Types::Int64> ((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch()) / TimeUnitRatio::k_US_PER_H) && -hours <= static_cast<bsls::Types::Int64> (microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_H)) { addHours(hours); return k_SUCCESS; // RETURN } return k_FAILURE; } inline Datetime& Datetime::addMinutes(bsls::Types::Int64 minutes) { BSLS_ASSERT_SAFE( minutes <= static_cast<bsls::Types::Int64> ((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch()) / TimeUnitRatio::k_US_PER_M)); BSLS_ASSERT_SAFE(-minutes <= static_cast<bsls::Types::Int64> (microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_M)); bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch(); setMicrosecondsFromEpoch(minutes * TimeUnitRatio::k_US_PER_M + totalMicroseconds); return *this; } inline int Datetime::addMinutesIfValid(bsls::Types::Int64 minutes) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if ( minutes <= static_cast<bsls::Types::Int64> ((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch()) / TimeUnitRatio::k_US_PER_M) && -minutes <= static_cast<bsls::Types::Int64> (microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_M)) { addMinutes(minutes); return k_SUCCESS; // RETURN } return k_FAILURE; } inline Datetime& Datetime::addSeconds(bsls::Types::Int64 seconds) { BSLS_ASSERT_SAFE( seconds <= static_cast<bsls::Types::Int64> ((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch()) / TimeUnitRatio::k_US_PER_S)); BSLS_ASSERT_SAFE(-seconds <= static_cast<bsls::Types::Int64> (microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_S)); bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch(); setMicrosecondsFromEpoch(seconds * TimeUnitRatio::k_US_PER_S + totalMicroseconds); return *this; } inline int Datetime::addSecondsIfValid(bsls::Types::Int64 seconds) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if ( seconds <= static_cast<bsls::Types::Int64> ((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch()) / TimeUnitRatio::k_US_PER_S) && -seconds <= static_cast<bsls::Types::Int64> (microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_S)) { addSeconds(seconds); return k_SUCCESS; // RETURN } return k_FAILURE; } inline Datetime& Datetime::addMilliseconds(bsls::Types::Int64 milliseconds) { BSLS_ASSERT_SAFE( milliseconds <= static_cast<bsls::Types::Int64> ((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch()) / TimeUnitRatio::k_US_PER_MS)); BSLS_ASSERT_SAFE(-milliseconds <= static_cast<bsls::Types::Int64> (microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_MS)); bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch(); setMicrosecondsFromEpoch(milliseconds * TimeUnitRatio::k_US_PER_MS + totalMicroseconds); return *this; } inline int Datetime::addMillisecondsIfValid(bsls::Types::Int64 milliseconds) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if ( milliseconds <= static_cast<bsls::Types::Int64> ((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch()) / TimeUnitRatio::k_US_PER_MS) && -milliseconds <= static_cast<bsls::Types::Int64> (microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_MS)) { addMilliseconds(milliseconds); return k_SUCCESS; // RETURN } return k_FAILURE; } inline Datetime& Datetime::addMicroseconds(bsls::Types::Int64 microseconds) { BSLS_ASSERT_SAFE( microseconds <= static_cast<bsls::Types::Int64> (k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())); BSLS_ASSERT_SAFE(-microseconds <= static_cast<bsls::Types::Int64> (microsecondsFromEpoch())); bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch(); setMicrosecondsFromEpoch(microseconds + totalMicroseconds); return *this; } inline int Datetime::addMicrosecondsIfValid(bsls::Types::Int64 microseconds) { enum { k_SUCCESS = 0, k_FAILURE = -1 }; if ( microseconds <= static_cast<bsls::Types::Int64> (k_MAX_US_FROM_EPOCH - microsecondsFromEpoch()) && -microseconds <= static_cast<bsls::Types::Int64> (microsecondsFromEpoch())) { addMicroseconds(microseconds); return k_SUCCESS; // RETURN } return k_FAILURE; } // Aspects template <class STREAM> STREAM& Datetime::bdexStreamIn(STREAM& stream, int version) { if (stream) { switch (version) { // switch on the schema version case 2: { bsls::Types::Uint64 tmp; stream.getUint64(tmp); if ( stream && tmp <= (DatetimeImpUtil::k_MAX_VALUE & (~k_REP_MASK))) { d_value = tmp; d_value |= k_REP_MASK; } else { stream.invalidate(); } } break; case 1: { Date date; Time time; date.bdexStreamIn(stream, 1); time.bdexStreamIn(stream, 1); if (stream) { setDatetime(date, time); } else { stream.invalidate(); } } break; default: { stream.invalidate(); // unrecognized version number } } } return stream; } // ACCESSORS inline Date Datetime::date() const { bsls::Types::Uint64 value = updatedRepresentation() & (~k_REP_MASK); return Date() + static_cast<int>(value >> k_NUM_TIME_BITS); } inline int Datetime::day() const { return date().day(); } inline DayOfWeek::Enum Datetime::dayOfWeek() const { return date().dayOfWeek(); } inline int Datetime::dayOfYear() const { return date().dayOfYear(); } inline void Datetime::getTime(int *hour, int *minute, int *second, int *millisecond, int *microsecond) const { bsls::Types::Uint64 microseconds = updatedRepresentation() & k_TIME_MASK; if (hour) { *hour = static_cast<int>(microseconds / TimeUnitRatio::k_US_PER_H); } if (minute) { *minute = static_cast<int>( microseconds / TimeUnitRatio::k_US_PER_M % TimeUnitRatio::k_M_PER_H); } if (second) { *second = static_cast<int>( microseconds / TimeUnitRatio::k_US_PER_S % TimeUnitRatio::k_S_PER_M); } if (millisecond) { *millisecond = static_cast<int>( microseconds / TimeUnitRatio::k_US_PER_MS % TimeUnitRatio::k_MS_PER_S); } if (microsecond) { *microsecond = static_cast<int>( microseconds % TimeUnitRatio::k_US_PER_MS); } } inline int Datetime::hour() const { bsls::Types::Uint64 microseconds = updatedRepresentation() & k_TIME_MASK; return static_cast<int>(microseconds / TimeUnitRatio::k_US_PER_H); } inline int Datetime::microsecond() const { bsls::Types::Uint64 microseconds = updatedRepresentation() & k_TIME_MASK; return static_cast<int>(microseconds % TimeUnitRatio::k_US_PER_MS); } inline int Datetime::millisecond() const { bsls::Types::Uint64 microseconds = updatedRepresentation() & k_TIME_MASK; return static_cast<int>( microseconds / TimeUnitRatio::k_US_PER_MS % TimeUnitRatio::k_MS_PER_S); } inline int Datetime::minute() const { bsls::Types::Uint64 microseconds = updatedRepresentation() & k_TIME_MASK; return static_cast<int>( microseconds / TimeUnitRatio::k_US_PER_M % TimeUnitRatio::k_M_PER_H); } inline int Datetime::month() const { return date().month(); } inline int Datetime::second() const { bsls::Types::Uint64 microseconds = updatedRepresentation() & k_TIME_MASK; return static_cast<int>( microseconds / TimeUnitRatio::k_US_PER_S % TimeUnitRatio::k_S_PER_M); } inline Time Datetime::time() const { int hour; int minute; int second; int millisecond; int microsecond; getTime(&hour, &minute, &second, &millisecond, µsecond); return Time(hour, minute, second, millisecond, microsecond); } inline int Datetime::year() const { return date().year(); } // Aspects template <class STREAM> STREAM& Datetime::bdexStreamOut(STREAM& stream, int version) const { if (stream) { switch (version) { // switch on the schema version case 2: { bsls::Types::Uint64 value = updatedRepresentation() & (~k_REP_MASK); stream.putUint64(value); } break; case 1: { date().bdexStreamOut(stream, 1); time().bdexStreamOut(stream, 1); } break; default: { stream.invalidate(); // unrecognized version number } } } return stream; } #ifndef BDE_OPENSOURCE_PUBLICATION // pending deprecation inline int Datetime::maxSupportedBdexVersion() { return maxSupportedBdexVersion(0); } #endif // BDE_OPENSOURCE_PUBLICATION -- pending deprecation #ifndef BDE_OMIT_INTERNAL_DEPRECATED // BDE2.22 inline int Datetime::maxSupportedVersion() { return maxSupportedBdexVersion(0); } inline bsl::ostream& Datetime::streamOut(bsl::ostream& stream) const { return stream << *this; } inline int Datetime::validateAndSetDatetime(int year, int month, int day, int hour, int minute, int second, int millisecond) { return setDatetimeIfValid(year, month, day, hour, minute, second, millisecond); } #endif // BDE_OMIT_INTERNAL_DEPRECATED -- BDE2.22 } // close package namespace // FREE OPERATORS inline bdlt::Datetime bdlt::operator+(const Datetime& lhs, const bsls::TimeInterval& rhs) { Datetime result(lhs); return result += rhs; } inline bdlt::Datetime bdlt::operator+(const bsls::TimeInterval& lhs, const Datetime& rhs) { Datetime result(rhs); return result += lhs; } inline bdlt::Datetime bdlt::operator+(const Datetime& lhs, const DatetimeInterval& rhs) { Datetime result(lhs); return result += rhs; } inline bdlt::Datetime bdlt::operator+(const DatetimeInterval& lhs, const Datetime& rhs) { Datetime result(rhs); return result += lhs; } inline bdlt::Datetime bdlt::operator-(const Datetime& lhs, const bsls::TimeInterval& rhs) { Datetime result(lhs); return result -= rhs; } inline bdlt::Datetime bdlt::operator-(const Datetime& lhs, const DatetimeInterval& rhs) { Datetime result(lhs); return result -= rhs; } inline bdlt::DatetimeInterval bdlt::operator-(const Datetime& lhs, const Datetime& rhs) { bsls::Types::Uint64 lhsTotalMicroseconds = lhs.microsecondsFromEpoch(); bsls::Types::Uint64 rhsTotalMicroseconds = rhs.microsecondsFromEpoch(); if (lhsTotalMicroseconds >= rhsTotalMicroseconds) { lhsTotalMicroseconds -= rhsTotalMicroseconds; return bdlt::DatetimeInterval( 0, 0, 0, 0, 0, lhsTotalMicroseconds); // RETURN } rhsTotalMicroseconds -= lhsTotalMicroseconds; return bdlt::DatetimeInterval( 0, 0, 0, 0, 0, -static_cast<bsls::Types::Int64>(rhsTotalMicroseconds)); } inline bool bdlt::operator==(const Datetime& lhs, const Datetime& rhs) { bsls::Types::Uint64 lhsValue = lhs.updatedRepresentation(); bsls::Types::Uint64 rhsValue = rhs.updatedRepresentation(); return lhsValue == rhsValue; } inline bool bdlt::operator!=(const Datetime& lhs, const Datetime& rhs) { bsls::Types::Uint64 lhsValue = lhs.updatedRepresentation(); bsls::Types::Uint64 rhsValue = rhs.updatedRepresentation(); return lhsValue != rhsValue; } inline bool bdlt::operator<(const Datetime& lhs, const Datetime& rhs) { BSLS_ASSERT_SAFE(24 != lhs.hour()); BSLS_ASSERT_SAFE(24 != rhs.hour()); bsls::Types::Uint64 lhsValue = lhs.updatedRepresentation(); bsls::Types::Uint64 rhsValue = rhs.updatedRepresentation(); return lhsValue < rhsValue; } inline bool bdlt::operator<=(const Datetime& lhs, const Datetime& rhs) { BSLS_ASSERT_SAFE(24 != lhs.hour()); BSLS_ASSERT_SAFE(24 != rhs.hour()); bsls::Types::Uint64 lhsValue = lhs.updatedRepresentation(); bsls::Types::Uint64 rhsValue = rhs.updatedRepresentation(); return lhsValue <= rhsValue; } inline bool bdlt::operator>(const Datetime& lhs, const Datetime& rhs) { BSLS_ASSERT_SAFE(24 != lhs.hour()); BSLS_ASSERT_SAFE(24 != rhs.hour()); bsls::Types::Uint64 lhsValue = lhs.updatedRepresentation(); bsls::Types::Uint64 rhsValue = rhs.updatedRepresentation(); return lhsValue > rhsValue; } inline bool bdlt::operator>=(const Datetime& lhs, const Datetime& rhs) { BSLS_ASSERT_SAFE(24 != lhs.hour()); BSLS_ASSERT_SAFE(24 != rhs.hour()); bsls::Types::Uint64 lhsValue = lhs.updatedRepresentation(); bsls::Types::Uint64 rhsValue = rhs.updatedRepresentation(); return lhsValue >= rhsValue; } // FREE FUNCTIONS template <class HASHALG> inline void bdlt::hashAppend(HASHALG& hashAlg, const Datetime& object) { using ::BloombergLP::bslh::hashAppend; hashAppend(hashAlg, object.updatedRepresentation()); } } // close enterprise namespace namespace bsl { // TRAITS template <> struct is_trivially_copyable<BloombergLP::bdlt::Datetime> : bsl::true_type { // This template specialization for 'is_trivially_copyable' indicates that // 'bdlt::Datetime' 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 ----------------------------------