Vision Class: Date

Overview

Dates are objects that represent a specific day in the calendar. Any historical or future date can be represented in Vision. It is not meaningful to create new instances of the Date class.

The class DateOffset is an abstract class that supports the protocol for different date increments: BusinessDays, Days, MonthBeginnings, MonthEnds, Months, QuarterBeginnings, QuarterEnds, Quarters, YearBeginnings, YearEnds, and Years. You create instances of the DateOffset subclasses to represent increments that can be added to or subtracted from a Date.

The class DateRange represents a range of dates of a specific frequency. You create instances of this class to define specific intervals of dates for evaluation.

The Date and DateOffset classes are direct subclasses of the class Ordinal. The DateRange class is a subclass of Object:

          Object
             |
             |-- DateRange
             |
             |-- Ordinal
                   |
                   |-- Date
                   |
                   |-- DateOffset
                         |-- BusinessDays
                         |-- Days
                         |-- MonthBeginnings
                         |-- MonthEnds
                         |-- Months
                         |-- QuarterBeginnings
                         |-- QuarterEnds
                         |-- Quarters
                         |-- YearBeginnings
                         |-- YearEnds
                         |-- Years


Creating Dates and DateOffsets

The instances of the class Date represent a specific day in the calendar. You can create a date object by sending the asDate message to an Integer in one of the following forms:

Format Example Returns the String
YYYYMMDD 19960614 asDate June 14, 1996
YYMMDD 960614 asDate June 14, 1996
YYMM 9606 asDate June 30, 1996 (month-end)
YY 96 asDate Dec 31, 1996 (year-end)

The magic word ^today returns the date object representing the current date. The message earliestPossibleDate has been defined at the class Object to return the Date object representing the first valid date that can be represented in Vision. This date corresponds to the first of January in the year 1.

You can add and subtract DateOffsets from a Date to create new date objects. For example:

     95 asDate + 5 days
returns the date object representing Jan 5, 1996 and:
     ^today - 1 months
returns the object representing the date one month prior to the current date.

Eleven DateOffset subclasses have been defined: Days, BusinessDays, Months, MonthBeginnings, MonthEnds, Quarters, QuarterBeginnings, QuarterEnds, Years, YearBeginnings, and YearEnds.

Valid DateOffset instances are formed by sending one of the following messages to an Integer:

Message Example Returns Date
days 95 asDate + 6 days Jan 6, 1996
businessDays 95 asDate + 6 businessDays Jan 8, 1996
months 951215 asDate - 1 months Nov 15, 1995
monthBeginnings 951215 asDate - 1 monthBeginnings Nov 1, 1995
monthEnds 951215 asDate - 1 monthEnds Nov 30, 1995
quarters 951215 asDate - 1 quarters Sept 15, 1995
quarterBeginnings 951215 asDate - 1 quarterBeginnings July 1, 1995
quarterEnds 951215 asDate - 1 quarterEnds Sept 30, 1995
years 951215 asDate - 1 years Dec 15, 1994
yearBeginnings 951215 asDate - 1 yearBeginnings Jan 1, 1994
yearEnds 951215 asDate - 1 yearEnds Dec 31, 1994

When a DateOffset is added to or subtracted from a Date, another Date object is returned. Since the returned object is a Date you can add or subtract an offset from it as well. For example:

     ^today - 1 yearEnds + 3 days
returns the third day of the current year.

Calculations that involve BusinessDays will only return Monday through Friday dates. Calculations that involve MonthBeginnings, QuarterBeginnings, or YearBeginnings, will only return dates that are the first day of the month, quarter, or year. Calculations that involve MonthEnds, QuarterEnds, or YearEnds, will only return dates that are the last day of the month, quarter, or year.

Calculations that involve Months, Quarters, or Years, will return dates that are on the same day in the month, as long as the date is valid. For example, the expression:

     960430 asDate - 1 months
returns the date March 30, 1996. The expression:
     960331 asDate - 1 months
returns the date February 29, 1996 since February 31 is not a valid date.

Date offsets that are formed by sending an increment message to the integer value 0 are used to convert a Date to a boundary relative to its current value. The following table defines these boundaries:

Example Returns Date Definition
95 asDate + 0 businessDays Dec 29, 1995 Convert Saturday and Sunday dates to prior Friday
95 asDate + 0 monthBeginnings Dec 1, 1995 First day in recipient's month
95 asDate + 0 monthEnds Dec 31, 1995 Last day in recipient's month
9511 asDate + 0 quarterBeginnings Oct 1, 1995 First day in recipient's quarter
9511 asDate + 0 quarterEnds Dec 31, 1995 Last day in recipient's quarter
9511 asDate + 0 yearBeginnings Jan 1, 1995 First day in recipient's year
9511 asDate + 0 yearEnds Dec 31, 1995 Last day in recipient's year


Basic Usage

All dates respond to the messages month, day, and year, returning integer values. For example:

     960615 asDate month
returns 6,
     960615 asDate day
returns 15, and
     960615 asDate year
returns 1996.

By default, dates print in the format month/day/year. For example:

     96 asDate print ;
displays:
     12/31/1996
The print: message prints dates in different formats, depending on the value of the supplied parameter. More information about printing dates is available.

The asInteger message can be used to convert a date to an eight-digit integer in the form YYYYMMDD. The following additional messages can be used to format date objects. They return an instance of the class String:

Message Sample Returns
formatUsingMMDD 95 asDate formatUsingMMDD "12/31"
formatUsingMMDDYY 95 asDate formatUsingMMDDYY "12/31/95"
formatUsingMMDDYYYY 95 asDate formatUsingMMDDYYYY "12/31/1995"
formatUsingShortName 95 asDate formatUsingShortName "31-Dec-1995"
formatUsingLongName 95 asDate formatUsingLongName "December 31, 1995"

The message getMonthDescriptor returns an instance of the class Date MonthDescriptor. This class has 12 instances, one for each month. Instances of this class respond to the messages shortName and longName. The getMonthDescriptor message returns the instance corresponding to the recipient date's month. For example:

     960615 asDate getMonthDescriptor shortName
returns the string "Jun". The MonthDescriptor class was created using the createSubclass:at: variation of the createSubclass: message so the class is only visible to Date objects.

The message getDayOfWeekDescriptor returns an instance of the class Date DayOfWeekDescriptor. This class has 7 instances, one for each day of the week. The message code returns the name of the day of the week. For example:

     960615 asDate getDayOfWeekDescriptor code
returns the string "Saturday". The message dayOfWeek has been defined at the Date class to return this value as well. The DayOfWeekDescriptor class was created using the createSubclass:at: variation of the createSubclass: message so the class is only visible to Date objects.

In addition to the asDate message, the following messages can be used to convert Integer instances to Date instances:

Message Definition Sample
asDateFromMMDD Convert recipient in MMDD format to a Date object 0315 asDateFromMMDD
asDateFromMMDDYY Convert recipient in MMDDYY format to a Date object 031595 asDateFromMMDDYY
asDateFromMMDDYYYY Convert recipient in MMDDYYYY format to a Date object 03151995 asDateFromMMDDYYYY
asDateFromMMYY Convert recipient in MMYY format to a Date object 0395 asDateFromMMYY
asDateFromYYYYMM Convert recipient in YYYYMM format to a Date object 199503 asDateFromYYYYMM
asMonthEnd Convert recipient month (1 - 12) to month-end Date in current year 9 asMonthEnd
asMonthEndInYear: Convert recipient month (1 - 12) to month-end Date in parameter year 9 asMonthEndInYear: 1995

In addition to the + offset and - offset messages, The following messages can be used to derive a Date instance from another Date:

Message Definition Sample
asBDay Convert recipient to prior Friday's date if it is a Saturday or Sunday; otherwise, return recipient 960615 asDate asBDay
asBDayMonday Convert recipient to following Monday's date if it is a Saturday or Sunday; otherwise, return recipient 960615 asDate asBDayMonday
asCurrentYearMMDD Convert recipient to the same month/day in current year 920615 asDate asCurrentYearMMDD
asMonthEnd Convert recipient to last day of its month 960615 asDate asMonthEnd
asMostRecentMonthEnd Convert recipient to last day in the month on or or before the recipient 960615 asDate asMostRecentMonthEnd
asQuarterEnd Convert recipient to last day in quarter 960615 asDate asQuarterEnd
asYearBeginning Convert recipient to first date in year 960615 asDate asYearBeginning
asYearEnd Convert recipient to last date in year 960615 asDate asYearEnd


Dates and TimeSeries Data

Date objects play an important role in accessing and updating time-series data. Dates (or integer equivalents) are the parameters for the asOf: and asOf:put: messages define for the TimeSeries class. For example:

     Named Currency CAD :usExchange asOf: 950315 asDate
returns the Canadian Dollar exchange rate as of March 15, 1995. The expression:
     Named Currency CAD :usExchange asOf: 951315 put: 1.23 ;
sets the March 15th value to 1.23.

When a message retrieves data stored in a time-varying property, it accesses the data as of a specific date. By default, this date is the current date. For example:

     Named Currency CAD usExchange
returns the most recent exchange rate for the Canadian Dollar.

The evaluate: message is sent to a Date or an Integer that can be converted to a date and is used to change the default date. The parameter to this message is a block. All messages within the block that access time series properties will access the values as of this date by default. For example:

     950315 evaluate:
       [ Named Currency CAD usExchange printNL ] ;
In this case, the exchange rate is accessed as of March 15, 1995. The magic word ^date refers to the default date. For example:
     950315 evaluate:
       [ ^date print: 15 ;
         Named Currency CAD usExchange printNL ;
       ] ;

This example displays the date 3/15/1995 followed by the exchange rate. You can change the default date within the evaluate: block. For example:

     950315 evaluate:
       [ ^date print: 15 ;
         Named Currency CAD usExchange printNL ;
         ^date + 5 businessDays evaluate:
             [ ^date print: 15 ; Named Currency CAD usExchange printNL ] ;
       ] ;
This examples displays the date 3/15/1995 followed by the exchange rate for that date. It then displays the date and exchange rate for the date 5 business days later than the original date.


Note:
The evaluate: message changes the time context of the block but does not change the recipient object like the do: message. In other words, the magic word ^date is rebound by the evaluate: message but the magic word ^self is not. If you send the do: message to a Date, messages within the block will be sent to the recipient date object (i.e., ^self is rebound). The magic word ^date will not use this date. For example:
     960315 asDate
     do: [ ^date print ;        #- will be ^today
           month print ; year printNL ;
         ] ;

     960315 asDate
     evaluate:
         [ ^date print ;       #- will be 3/15/96
           ^date month print ; ^date year printNL ;
         ] ;



Date Arithmetic and Internal Dates

The + offset and - offset messages are used to compute a date based on another date. Several messages are also defined that allow you to perform computations between dates.

Date arithmetic is facilitated by the internal representation of the date objects. Internally, dates are stored as integers numbered consecutively from 1. This value can be accessed by sending the asIDate7 (integer form using 7-day weeks) message to a Date. For example:

     95 asDate asIDate7
returns the integer value 728,658. Since dates are number consecutively, internal dates can be used to compute the number of days between two dates. For example:
     !date1 <- 950315 asDate; 
     !date2 <- 950322 asDate ; 
     (date2 asIDate7 - date1 asIDate7 ) asInteger print ;
prints the value 7. The message countDaysTo: performs this same function. For example:
     !date1 <- 950315 asDate; 
     !date2 <- 950322 asDate ; 
     date1 countDaysTo: date . asInteger print ;


Other Date Messages

The following messages perform basic comparison operations between the recipient Date and parameter Date. These messages return an instance of the Boolean class except where noted.

Message Definition Sample
= Is recipient equal to parameter? ^today = ^date
== Is recipient identical to parameter? ^today == ^date
!= Is recipient not equal to parameter? ^today != ^date
!== Is recipient not identical to parameter? ^today !== ^date
< Is recipient less than parameter? ^today < ^date
<= Is recipient less than or equal to parameter? ^today <= ^date
> Is recipient greater than parameter? ^today > ^date
>= Is recipient greater than or equal to parameter? ^today >= ^date
between:and: Is recipient value between two parameter values? ^today between: 95 asDate and: 96 asDate .
inRange: Is recipient value in the range implied by the parameter, a list of two elements representing the start and end of the range inclusively? ^today inRange: 95 asDate, 96 asDate .
inSet: Is recipient equal to one of the values in the parameter, a list containing one or more elements? ^today inSet: 94 asDate, 95 asDate, 96 asDate .
notBetween:and: Is recipient value not between two parameter values? ^today notBetween: 95 asDate and: 96 asDate .
max: Returns the larger of recipient and parameter value ^today max: ^date .
min: Returns the smaller of recipient and parameter value ^today min: ^date .

The following messages perform basic inquiries about the recipient. These messages return an instance of the Boolean class.

Message Definition Sample
isMonthEnd Is recipient a month-end date? ^today isMonthEnd
isLastBusinessDayOfMonth Is recipient the last business day of the month? ^today isLastBusinessDayOfMonth
isInitialDate Is recipient the earliest possible date? ^today isInitialDate


Date Ranges

A DateRange is defined by specifying a starting date, and ending date, and a date offset. Starting and ending dates can be any date or an integer that can be converted to a valid date.

The general form for creating a date range is:

     !dr <- date1 to: date2 by: offset ;
For example:
     #--  define date range of month-end dates in 1995
     !dr1 <- 9501 to: 9512 by: 1 monthEnds ;

     #--  define weekly dates back one year
     !dr2 <- ^today to: ^today - 1 years by: 5 businessDays ;

DateRange objects respond to the date1, date2, and increment messages by returning the starting date, the ending date, and the date offset used to define the date range.

DateRanges respond to the evaluate: message by executing the block supplied as a parameter, once for each point in the date range. For example:

     9501 to: 9512 by: 1 monthEnds .
     evaluate: [ ^date print: 15 ; 
                 Named Currency CAD usExchange printNL ;
               ] ;
In this example, the US exchange rate for the Canadian currency is printed for each month-end date in 1995. The supplied block prints the evaluation date and the exchange rate. Starting with the initial date (i.e., January 31, 1995), Vision processes this block for each date in the date range, incrementing the evaluation date by the date range's offset (i.e., 1 monthEnds) until the ending date (i.e., December 31, 1995) is crossed. The magic word ^date reflects the specific evaluation date within the range as it is processing.

Date ranges can be executed in reverse order as well. When the starting date in a date range is later than the ending date, Vision will decrement the evaluation date by the offset provided. For example, if the date range in the previous example were defined using: 9512 to: 9501 by: 1 monthEnds, the exchange rates would be displayed starting with December 1995 and ending with January 1995.


Note:
The evaluate: message changes the time context of the block but does not change the recipient object like the do: message. In other words, the magic word ^date is rebound by the evaluate: message but the magic word ^self is not.

The evaluate: message is defined to evaluate its block parameter for each element in the date range. Although this operation may appear to operate a date at a time, it is actually optimized internally and does not execute by sequential evaluation.


Warning!!
Because date ranges are not evaluated sequentially, you do not have control over the order in which the date range is processed nor can you assume that the number of evaluations is equal to the number of elements in the range.

The iterate: message can be used instead of evaluate: when you want to evaluate the date range an element at a time. For example:

     9501 to: 9512 by: 1 monthEnds .
      iterate: [ ^date print: 15 ; 
                 Named Currency CAD usExchange printNL ;
               ] ;

You can convert a DateRange into a List of Date objects using the asDateList message. For example:

     !drange <- 9501 to: 9512 by: 1 monthEnds ;
     !dlist <- drange asDateList ;
     dlist count print ;
The variable dlist returns a List of 12 date objects. Note that the magic word ^date will not be associated with these objects. For example:
     dlist do: [ ^date print: 15 ; printNL ; ] ;
In this example, the same value will print for ^date for each element in dlist. The actual value of the Date will print as the second item in the line.

The message extract:for: is used to execute a program for an object over a date range, returning a TimeSeries. For example:

     9501 to: 9512 by: 1 monthEnds .
        extract: [ usExchange ] for: Named Currency CAD
returns a time series of twelve month-end exchange rates for the Canadian currency.


Additional Information

For additional information see: