Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdlt_datetime
[Package bdlt]

Provide a value-semantic type representing both date and time. More...

Namespaces

namespace  bdlt

Detailed Description

Outline
Purpose:
Provide a value-semantic type representing both date and time.
Classes:
bdlt::Datetime date and time value (at least microsecond resolution)
See also:
Component bdlt_date, Component bdlt_time, Component 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.