Essential Tools Module User's Guide : Chapter 3 Date and Time Classes : RWDateTime : RWDateTime Sentinels
RWDateTime Sentinels
RWDateTime has the ability to hold sentinel values that are not necessarily dates, but are convenient to use as comparison values within applications. For example, a “future” sentinel provides a value that represents a date larger than the largest RWDateTime. RWDateTime currently provides four internal, pre-defined sentinels and can accommodate up to 128 user-defined sentinels. The RWDateTime sentinels are described in the following sections.
Table 3 summarizes the responses of RWDateTime operations when applied to various sentinels. The sections that follow Table 3 provide more information about the sentinels.
Table 3 – RWDateTime sentinels  
Operator/Function
Valid
Null
Invalid
Past/Future
User Sentinel
Extract Part
OK
RWTHROW
RWTHROW
RWTHROW
RWTHROW
Arithmetic
OK
Propagate to Invalid
Propagate
Propagate Past/Future
Propagate to Invalid
Relational
OK
OK
OK
OK
OK
asString()/Output
OK
“NULL”
“#INVALID#”
“#INVALID#”
“#>num<#”
Read String
OK
N/A
OK
N/A
N/A
Create
OK
OK
OK
OK
OK
NOTE >> Attempting to calculate the time differential between two RWDateTime objects (utilizing the – operator) results in the throwing of an RWInternalErr if either of the RWDateTime objects are sentinels.
The “Invalid” Sentinel and Other Invalid Instances
The Essential Tools Module allows for RWDateTime instances with an “invalid” state that can be compared to other RWDateTime instances and can be persisted. The default RWDateTime constructor constructs an invalid instance, and other construction techniques are available, including the RWDateTime::invalidSentinel constant. You can pass this constant to the RWDateTime(rwint64) constructor to create instances of the minimum and maximum RWDateTime as needed, or you can use it to compare directly with the millisecond count returned by RWDateTime::milliSeconds().
No other operations work, other than persisting the invalid object and using it in comparisons of equality and inequality. Arithmetic manipulation of an invalid RWDateTime results in an invalid RWDateTime. Attempts to use the part extraction functions (day(), month(), extract(), etc.) result in an RWInternalErr being thrown by RWTHROW. The asString() family of functions always return the string "#INVALID#" when called with an invalid RWDateTime.
The following examples show several ways to construct an RWDateTime with an invalid state:
 
// construct dt1 with invalid state:
RWDateTime dt1;
 
// construct dt2 with invalid state:
RWDateTime dt2(RWDateTime::invalid);
 
// construct dt3 with invalid state:
RWDateTime dt3(RWDateTime::invalidSentinel);
 
// construct dt4 with invalid state:
RWDateTime dt4(RWDate(29,02,1997));
The “Null” Sentinel
Sometimes it is convenient to have an RWDateTime that is valid yet holds no specific value. The Essential Tools Module includes the “null” state sentinel for this purpose. You can construct a null RWDateTime or use the constant RWDateTime::nullSentinel in construction by passing the constant RWDateTime::nullSentinel to the RWDateTime(rwint64) constructor. You can also use the constant in direct comparisons with the millisecond count returned by RWDateTime::milliSeconds().
Comparison operations for equality and inequality do work, with an RWDateTime in a “null” state always being less than a valid RWDateTime. Arithmetic manipulation of a null RWDateTime results in an invalid RWDateTime. Attempts to use any part extraction functions (day(), month(), extract(), etc.) result in an RWInternalErr being thrown by RWTHROW. The asString() family of functions always return the string NULL when called for a null RWDateTime.
The following examples show how to construct an RWDateTime with a null state, and demonstrate what happens when it is used in an arithmetic operation:
 
// construct dt1 with null state:
RWDateTime dt1(RWDateTime::null);
 
// construct dt2 with null state
RWDateTime dt2(RWDateTime::nullSentinel);
 
// attempted arithmetic manipulation:
assert(dt2.isValid());
dt2.incrementMillisecond(23); // dt2 set to invalid state
assert(dt2.isValid()); // invalid
The Past and Future Sentinels
When sorting and searching for RWDateTime objects it is useful to have sentinels that represent “smaller than the smallest” RWDateTime and “larger than the largest” RWDateTime. The “past” and “future” sentinels are special kinds of invalid sentinels.
RWDateTime includes two global static constants to determine the minimum and maximum valid RWDateTime objects: RWDateTime::minDateTime and RWDateTime::maxDateTime. You can pass these constants to the RWDateTime(rwint64) constructor to create instances of the minimum and maximum RWDateTime as needed, or you can use them to compare directly with the millisecond count returned by RWDateTime::milliSeconds().
The past and future sentinels can be used in any relational operation, and every valid RWDateTime falls strictly between the past and future sentinels. Arithmetic manipulation of past or future sentinels does not change their values, nor cause any error. Attempts to use any part extraction functions (day(), month(), extract(), etc.) result in an RWInternalErr being thrown by RWTHROW. The asString() family of functions always return the string "#INVALID#" for past and future sentinels.
Here are some examples of constructing and using past and future sentinels:
 
// construct a past sentinel
RWDateTime past(RWDateTime::pastSentinel);
// construct a future sentinel
RWDateTime future(RWDateTime::futureSentinel);
// construct an RWDateTime holding the largest valid time
RWDateTime maxDT(RWDateTime::maxDateTime);
// construct an RWDateTime holding the smallest valid time
RWDateTime minDT(RWDateTime::minDateTime);
 
bool a = past < minDT; // a == true
bool b = future > maxDT; // b == true
bool c = minDT.isValid(); // c == true
bool d = maxDT.isValid(); // d == true
bool e = !past.isValid(); // e == true
bool f = !future.isValid(); // f == true
User-Defined Sentinels
RWDateTime also provides for the use of 128 user-defined sentinels numbered 0 through 127. Each of these sentinels behaves like the null sentinel for part extraction functions, arithmetic manipulation, and relational operations. The asString() family of functions return "#>num<#" where num is the user sentinel number. The static method RWDateTime::userSentinel(int) is available for constructing user sentinels. These can be used to define different kind of dates, such as “refused”, for cases where a user has declined to enter data in a date field.
Here is an example of constructing and using user-defined sentinels:
 
RWDateTime sent0 = RWDateTime::userSentinel(0);
RWDateTime sent1 = RWDateTime::userSentinel(1);
std::cout << sent1.asString() << std::endl; // outputs #>1<#