Chapter 4. Using Class RWDate

Class RWDate represents a date, stored as a Julian day number. Commonly used in software, this compact representation allows rapid calendar calculations, shields you from details such as leap years, and performs easy conversions to and from conventional calendar formats.

You don't need to know Julian day numbers to benefit from their use in Tools.h++. If you are interested, the algorithm Tools.h++ uses to convert common calendar dates to Julian day numbers is given in "Algorithm 199" from Communications of the ACM, Volume 6, No. 8, Aug. 1963, p. 444.

The Gregorian calendar now used nearly world-wide was introduced by Pope Gregory XIII in 1582, and adopted in various places at various times. It was adopted by England on September 14, 1752, and thus came to the United States. We mention this because an RWDate for a day prior to the adoption of the Gregorian calendar is only valid in the sense that it is an extrapolation back from the Gregorian system. Printing such an RWDate , or using its methods to deal with specific day or month names, may have unexpected results.


The point is that RWDate allows you to quickly and easily manipulate the calendar dates you're most likely to use. Here is an example that demonstrates the virtuosity of the class.

Let's print out the date when ENIAC first started, 14 February 1945, then calculate and print the date of the previous Sunday, using the global locale:

#include <rw/rwdate.h>
#include <rw/rstream.h>
int main(){
  // ENIAC start date
  RWDate d(14, "February", 1945);
  // Today
  RWDate today;
  cout << d.asString("%A, %B %d 19%y")
       << " was the day the ENIAC computer was" << endl
       << "first turned on.  "
       << today - d << " days have gone by since then. " << endl;
  return 0;

Program Output:

Wednesday February 14, 1945 was the day the ENIAC computer was
first turned on.  18636 days have gone by since then.

In this calculation, notice that the number of days that have passed depends on when you run the program.


You can construct an RWDate in several ways. For example:

  1. Construct an RWDate with the current date[4] :

    RWDate d;

  2. Construct an RWDate for a given day of the year (1–365) and a given year, e.g., 1989 or 89. Although the class supports 2-digit year specifiers, we urge you to use the 4-digit variety if possible to void difficulties at the turn of the century.

    RWDate d1(24, 2001);                    // 1/24/2001
    RWDate d2(24, 01);                     // 1/24/1901 (oops)

  3. Construct an RWDate for a given day of the month (1–31), month number (1–12), and year:

    RWDate d(10, 3, 2015);                         // 3/10/2015

  4. Construct an RWDate from an RWTime:

    RWTime t;                                     // Current time.
    RWDate d(t);

In addition, you can construct a date using locale-specific strings. If you do nothing, a default locale using United States conventions and names is applied:

RWDate d1(10, "June", 2001);                         // 6/10/2001
RWDate d2(10, "JUN", 2001);                          // 6/10/2001

But suppose you need to use French month names. Assuming your system supports a French locale, here's how you might do it:

#include <rw/rwdate.h>
#include <rw/rstream.h>
#include <rw/locale.h>
#include <rw/cstring.h>
  RWLocaleSnapshot us("C");
  RWLocaleSnapshot french("fr");       // or vendor specific // 1
  RWCString americanDate("10 June 2025");
  RWCString frenchDate("10 Juin 2025");
  RWDate d(frenchDate, french);        // OK                 // 2
  cout << frenchDate << ((d.isValid()) ? " IS " : " IS NOT ")
       << "a valid date (french locale)." << endl << endl;
  RWDate bad = RWDate(frenchDate);                           // 3
  cout << frenchDate;
  cout << ((bad.isValid() && bad == d) ? " IS " : " IS NOT ")
       << "a valid date (default locale)." << endl << endl;
  bad = RWDate(americanDate, french;                         // 4
  cout << americanDate;
  cout << ((bad.isValid() && bad == d) ? " IS " : " IS NOT ")
       << "a valid date (french locale)." << endl << endl;
  cout << d << endl;                                         // 5
  cout << d.asString() << endl;                              // 6
  cout << d.asString('x', french) << endl;                   // 7
  return 0;

Here's a line-by-line description of the previous code:

  1. A snapshot is taken of locale fr. This assumes your system supports the locale. Another common name for this locale is fr_FR.

  2. A date is constructed using the constructor:

    RWDate(unsigned day,const char* month,unsigned year,
    const RWLocale& locale = RWLocale::global());

    Note that the second argument month is meaningful only within the context of a locale. In this case, we are using the locale constructed at line 1. The result is the date known in English as June 10, 2002.

  3. Here we attempt to construct the same date using the default locale. This locale recognizes C formatting conventions only. Hence, the date 10 Juin 2002 should be meaningless. Just in case, though, compare with a known valid date.

  4. For the same reason, constructing a date using United States names with a French locale should fail. Just in case, though, compare with a known valid date.

  5. The date constructed at line 2 is printed using the default locale, i.e., United States formatting conventions. The results are:


  6. The date is converted to a string, then printed. Again, the default locale is used. The results are the same:


  7. The date is converted to a string, this time using the locale constructed at line 1. The results are now[5] :


[4] Because the default constructor for RWDateRWDateRWDateRWTValOrderedVector<RWDate>.

[5] Your system's locale files determine the format used.