Vous êtes sur la page 1sur 13

TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

support.sas.com > Technical Support -- Navigate our Site --

TS Home | Intro to Services | News and Info | Contact TS | Site Map | FAQ | Feedback

TS-668

SAS Dates, Times, and Interval Functions


Definitions and Explanations
SAS Dates, Times, and Datetimes:

SAS date variables are numeric variables containing integer values. The range of usable values goes from -138,061
(January 01, 1582) to 6,589,335 (December 31, 20000). A value of 0 corresponds to January 01, 1960. The lower limit
is due to a change made to the Gregorian calendar in 1582. Most of the SAS date formats are limited to displaying 4
digit years making their limit December 31, 9999, however, the format WORDDATE20. will display 5 digit years. I'm
sure that this will be addressed before the year 10,000.

SAS time variables are also numeric variables. SAS times are a count of the number of seconds since midnight. They
can and often do contain decimal values representing fractions of a second. The range of values is 0 <= sas time <
86400. A SAS time variable having a value of 60 is 1 minute after midnight. 12:00 noon would be stored internally as
43200. midnight is stored as 0. If a SAS time variable has a value larger than 86400, different formats treat the value
differently. The TIMEAMPM. format uses a 12 hour clock so all values of the hour will be between 1 and 12 inclusive.
All others, for example, HHMMw. TIMEw. will display the number of hours in the time variable. Below is an example
of the differences:

0001
0002 data _null_;
0003 x=100000;
0004 put x timeampm8.;
0005 put x time8.;
0006 put x hhmm8.;
0007 run;

3:46 AM
27:46:40
27:47
NOTE: DATA statement used:
real time 0.03 seconds
cpu time 0.03 seconds

SAS datetime variables, like the others, are numeric variables. They can have decimal values, like time values,
because they have a time component. A SAS datetime value is the number of seconds before or after midnight January
01, 1960. Positive numbers are after that, and negative numbers are before. A datetime value of 253,717,747,199.00
TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

corresponds to 11:59:59 PM on December 31, 9999. This is the upper limit of a usable datetime. Again, greater
numbers can be used in calculations, however, they cannot be displayed with currently available formats. SAS can
extract the date or time portion of the value through the DATEPART and TIMEPART functions. Date variables can be
combined with time variables to create datetime variables with the DHMS function.

The following program uses these three functions to separate the date and time from a datetime value, then recombines
them with the DHMS function. Syntax for the DHMS function is :

RESULT=DHMS(date,hour,minute,second);

If you have a time value you do not have to separate out the hours, minutes, and seconds. You can use 0 for the hours
and minutes, and use the time variable for the seconds value. This method is used to create datetime2 below.

0001 data _null_;


0002 dt='14jun2004:06:32:30'dt;
0003 date=datepart(dt);
0004 time=timepart(dt);
0005 hh=hour(time);
0006 mm=minute(time);
0007 ss=second(time);
0008 put date= mmddyy10. /
0009 time= timeampm10.
0010 ;
0011 datetime1=dhms(date,hh,mm,ss);
0012 datetime2=dhms(date,0,0,time);
0013 put datetime1= datetime22. /
0014 datetime2= datetime22.
0015 ;
0016 run;

date=06/14/2004
time=6:32:30 AM
datetime1=14JUN2004:06:32:30
datetime2=14JUN2004:06:32:30
NOTE: DATA statement used:
real time 0.06 seconds
cpu time 0.05 seconds

Durations:

Durations fall into one of two catagories. Date durations are integer values representing the difference, in number of
days between two SAS dates. Time durations are decimal values representing the number of seconds between two
times, or datetimes. Date and datetime durations can be easily calculated by subtracting the smaller date or datetime
from the larger. When dealing with SAS times, special care must be taken if the beginning and end of a duration are on
different calendar days. When this is possible the simplest solution is to use datetimes rather than times. Another
possible solution, depending on the data involved, is to add 24 hours (86400 seconds) to the end time if it is smaller
than the start time, then subtract the start time from the end time. Again, this will only work in some situations. To
display the durations, use the TIMEw.d and HHMMw.d formats. They will display hour values greater than 24.

Intervals:
TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

Intervals are units of measurement that SAS can count within an elapsed period of time, such as DAYS, MONTHS, or
HOURS. The SAS System determines date and time intervals based on fixed points on the calendar and/or clock. The
starting point of an interval calculation defaults to the beginning of the period in which the beginning value falls, which
may not be the actual beginning value specified. For instance, if you are using the INTCK function to count months
between two dates, regardless of the actual day of the month specified by the date in the beginning value, SAS treats it
as the first of that month. More on this in the examples.

Duration Functions

SAS provides two functions in the DATA step that measure calendar durations.

● DATDIF
● YRDIF

DATDIF returns the number of days between two SAS dates. If datetime values are supplied, SAS treats them as dates.
The first parameter is the starting date, the second parameter is the ending date. The third parameter is called basis.
Basis tells SAS whether to use approximate or exact calculations. The two choices are

● '30/360' - 30 days each month, 360 days each year - Alias '360'
● 'ACT/ACT' - Actual days each month, Actual days each year - Alias 'ACTUAL'

The example below shows the difference.

0001
0002 data _null_;
0003 s='01jan2000'd;
0004 e='01jan2001'd;
0005 _360=datdif(s,e,'360');
0006 _act=datdif(s,e,'actual');
0007 put _360= _act=;
0008 run;

_360=360 _act=366
NOTE: DATA statement used:
real time 0.02 seconds
cpu time 0.02 seconds

YRDIF works the same way, however, YRDIF returns a floating point number rather than an integer. The basis can
have any of four values.

● 30/360 - 30 days each month, 360 days each year - Alias '360'
● ACT/ACT - Actual days each month, Actual days each year - Alias 'ACTUAL'
● ACT/360 - Actual days each month, 360 day each year - No Alias
● ACT/365 - Actual days each month, 365 day each year - No Alias

The following example shows the differences:

0001 data _null_;


0002 sdate='16mar1990'd;
0003 edate='16sep1994'd;
TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

0004 y30360_=yrdif(sdate, edate, '30/360');


0005 yactact=yrdif(sdate, edate, 'ACT/ACT');
0006 yact360=yrdif(sdate, edate, 'ACT/360');
0007 yact365=yrdif(sdate, edate, 'ACT/365');
0008 put y30360_= / yactact= / yact360= / yact365=;
0009 run;

y30360_=4.5
yactact=4.504109589
yact360=4.5694444444
yact365=4.5068493151
NOTE: DATA statement used:
real time 0.03 seconds
cpu time 0.03 seconds

Interval Functions

SAS provides two interval functions in the DATA step that count and manipulate calendar and clock intervals.

● INTCK
● INTNX

Simply stated, INTCK counts intervals and INTNX adjusts dates, times, or datetimes to interval boundaries. There are
three types of intervals: single-unit, multiunit, and shifted. The usage and results of the INTCK and INTNX functions
will vary somewhat with the different types. All three are covered below. To understand how INTCK and INTNX
work, first you must understand intervals and how SAS uses them.

Single-Unit Intervals

The following are the single-unit intervals and their boundaries on the calendar or clock. The beginning of each interval
is also listed.

Time units

SECOND - each second


MINUTE - each minute
HOUR - each hour

Date units

DAY - each day


WEEKDAY - each weekday (Monday through Friday by default)
WEEK - each Sunday
TENDAY - the First, Eleventh, and Twenty-first of each month
SEMIMONTH - the first and sixteenth of each month
MONTH - the first of each month
QTR - the first of January, April, July, and October
SEMIYEAR - the first of January and July
YEAR - the first of January

Datetime units
TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

DTDAY - each day


DTWEEKDAY - each weekday (Monday through Friday by default)
DTWEEK - each Sunday
DTTENDAY - the First, Eleventh, and Twenty-first of each month
DTSEMIMONTH - the first and sixteenth of each month
DTMONTH - the first of each month
DTQTR - the first of January, April, July, and October
DTSEMIYEAR - the first of January and July
DTYEAR - the first of January

INTCK

Using the INTCK function, an interval is counted when the boundary is crossed. In the following example the INTCK
function is used to count each of the calendar intervals. The starting date is November 30, 2000 and the ending date is
January 02, 2001. The result and explanation for each are shown below. The syntax for the INTCK function is:

RESULT=INTCK('INTERVAL',START,END);

0001 data _null_;


0002 start='30nov2000'd;
0003 end = '02jan2001'd;
0004 DAY = INTCK('DAY ',start,end);
0005 WEEK = INTCK('WEEK ',start,end);
0006 TENDAY = INTCK('TENDAY ',start,end);
0007 SEMIMONTH= INTCK('SEMIMONTH',start,end);
0008 MONTH = INTCK('MONTH ',start,end);
0009 QTR = INTCK('QTR ',start,end);
0010 SEMIYEAR = INTCK('SEMIYEAR ',start,end);
0011 YEAR = INTCK('YEAR ',start,end);
0012 put
0013 start = mmddyy10. /
0014 end = mmddyy10. /
0015 DAY = /
0016 WEEK = /
0017 TENDAY = /
0018 SEMIMONTH= /
0019 MONTH = /
0020 QTR = /
0021 SEMIYEAR = /
0022 YEAR = /
0023 ;
0024 run;

start=11/30/2000
end=01/02/2001
DAY=33
WEEK=5
TENDAY=4
SEMIMONTH=3
MONTH=2
QTR=1
TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

SEMIYEAR=1
YEAR=1
NOTE: DATA statement used:
real time 0.16 seconds
cpu time 0.10 seconds

DAY = 33
The DAY value of 33 is calculated by simple math. The START date 30NOV2000 in SAS date form has a value of
14944. The END date is 14977. Subtract END from START and the result is 33.

WEEK = 5
The WEEK value of 5 may not seem to make sense, since there are only 33 days between the two dates, but remember,
INTCK is counting interval boundaries. The boundary for WEEK is Sunday. Looking at the calendar there are five
Sundays between those dates: 03DEC2000, 10DEC2000, 17DEC2000, 24DEC2000, and 31DEC2000. Since INTCK
counts the number of Sundays, it returns a value of 5.

TENDAY = 4
TENDAY interval boundaries are the first, eleventh, and twenty-first of each month. For the sample values, these are
01DEC2000, 11DEC2000, 21DEC2000, and 01JAN2001 for a count of 4

SEMIMONTH = 3
SEMIMONTH counts 01DEC2000, 16DEC2000, and 01JAN2001 for a total of 3 intervals.

MONTH = 2
MONTH counts only the first of each month, December and January, for a total of 2.

QTR = 1
SEMIYEAR = 1
YEAR = 1
Each of the above count the same thing, 01JAN2001, because it is the boundary for each interval.

NOTE:An interval boundary is counted only when it is crossed. So if the starting day is the first day boundary, the
starting interval is not counted. For example, using the interval YEAR, a START of 01JAN2000, and an END of
31DEC2000, INTCK returns a value of zero. Change the END to 01JAN2001 and INTCK returns a value of one. The
boundary of 01JAN2000 is not counted because it is not crossed. Likewise change START to 31DEC2000 and END to
01JAN2001 and INTCK will return a value of one.

Consider another example. For the WEEK value, remember that INTCK counts the number of Sundays that lie between
the start date and the end date(including the end date), not the number of days divided by 7. So if the starting date is on
Saturday and the ending date on Monday, INTCK counts that as one week. Likewise, if the starting date falls on a
Friday and the ending date is 10 days later, INTCK counts two weeks because the interval crosses two Sundays.

INTNX

The INTNX function adjusts a SAS date, time, or datetime value forward or backward, and returns the adjusted date
value. You also have the ability to specify the alignment. Alignment is where you want the date, time, or datetime
adjusted, within the interval. The options are "Beginning", "Middle", and "End". "Beginning" is the default if not
specified. The following examples start with a base date of Saturday, April 15, 2000. The results show the effect of
different combinations of intervals and alignment. The number of combinations are far too numerous to do them all. All
of the above intervals generate different results based on alignment, with the exception of DAY. For simplicity the
resulting value is displayed in mmddyy10. format. The syntax of the INTNX function is:
TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

RESULT=INTNX('INTERVAL',START,INCREMENT<,'ALIGNMENT'>);

Start=04/15/2000
Interval=Year Increment=-1 Alignment=B Result=01/01/1999
Interval=Year Increment=-1 Alignment=M Result=07/02/1999
Interval=Year Increment=-1 Alignment=E Result=12/31/1999

Interval=Qtr Increment=0 Alignment=B Result=04/01/2000


Interval=Qtr Increment=0 Alignment=M Result=05/16/2000
Interval=Qtr Increment=0 Alignment=E Result=06/30/2000

Interval=Month Increment=12 Alignment=B Result=04/01/2001


Interval=Month Increment=12 Alignment=M Result=04/15/2001
Interval=Month Increment=12 Alignment=E Result=04/30/2001

Multiunit Intervals

NOTE:Multiweek intervals and boundaries are discussed in more detail below.

Multiunit intervals are multiples of single-unit intervals. They are used with the INTCK and INTNX functions the same
way as single-unit intervals. The syntax for specifying multiunit intervals requires adding the number of multiples
inside the quotes, for example "MONTH2".

Multiunit intervals, like single-unit intervals, are measured by the Gregorian calendar. SAS can easily determine single-
unit boundaries. SAS can also easily count single or multiunit intervals. However, when dealing with multiunit
intervals, finding the correct boundary presents a problem. For instance, if you need to count 90 day intervals SAS
needs to determine the boundaries. To accomplish this SAS begins at January 01, 1960 and counts forward or backward
in the multiples of the units specified to the starting point specified in the INTCK or INTNX function call. This may
seem confusing, but the example below should help clear things up.

This example counts the 90 day periods between January 01, 2000 and June 01, 2000. The actual number of days
between those two dates is 152. Dividing 152 by 90 and discarding any remainder yields a product of 1. So one would
expect the following program to produce a value of 1:

data _null_;
cnt=intck('day90','01jan2000'd, '03jun2000'd);
put cnt=;
run;

However, the SAS Log shows this:

0001 data _null_;


0002 cnt=intck('day90','01jan2000'd, '03jun2000'd);
0003 put cnt=;
0004 run;

CNT=2

Remember that SAS counts the number of times a boundary is crossed. To determine why SAS produced a value of 2
we need to determine the boundaries used. We can use the INTNX function to do this. When 0 is used for the
TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

increment value in the INTNX function, the value returned is the beginning of the interval that contains the START
value. Below is the example:

0001 data _null_;


0002 base=intnx('day90','01jan2000'd,0);
0003 put base= mmddyy10.;
0004 run;

base=12/02/1999

You can see that the start date specified in the previous program is already 30 days into the interval. The following
program determines the next two DAY90 boundaries so we can see what was counted. The program is included in the
following SAS Log:

0001 data _null_;


0002 base=intnx('day90','01jan2000'd,0);
0003 nxt1=intnx('day90','01jan2000'd,1);
0004 nxt2=intnx('day90','01jan2000'd,2);
0005 put base= mmddyy10. /
0006 nxt1= mmddyy10. /
0007 nxt2= mmddyy10. ;
0008 run;

base=12/02/1999
nxt1=03/01/2000
nxt2=05/30/2000

Here the INTCK function counted March 01, 2000 and May 30, 2000 for the result of 2 90-day intervals between
January 01, 2000 and June 03, 2000. SAS only counts the times that a boundary is crossed.

Because many date intervals align with the calendar year, this issue does not always come up. For instance, all of the
following single and multiunit boundaries align on the calendar year. In all these cases period shifting can be ignored.
This is a partial listing:

TENDAY, SEMIMONTH, MONTH, MONTH2, MONTH3, MONTH4, MONTH6, QTR, SEMIYEAR, and YEAR

Multiweek Boundaries

The boundaries are determined by counting from January 01, 1960 for all intervals with the exception of multiweek.
The starting date for all multiweek intervals is December 27, 1959. The reason for this is that the interval boundary for
WEEK begins on Sunday. Because January 01, 1960 fell on Friday, the beginning was moved back to the preceeding
Sunday.

SHIFTED-INTERVALS

You also have the ability to shift the beginning point or boundary of an interval. The boundary is moved forward on the
calendar, or clock by the number of shift-periods specified.

Intervals and shift periods

The general form for specifying an shifted interval is


TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

name < multiple > < .starting-point >

name is the name of the interval. See the following table for a list.

< multiple > expands the interval by the number of times specified. The default is 1. Multiple can be any positive
integer. It is an optional argument. Example: MONTH6 indicates a 6 month period. YEAR2 indicates a two year
interval.

<.starting-point> is the starting point or boundary you are defining. By default the starting point is 1. You can specify
any positive integer value up to the number of shift-periods available in the interval.

It is important to note that the boundary is shifted TO that number shift-period, not BY that number of shift-periods. As
an example, the intervals 'YEAR' and 'YEAR.1' produce the same results: the boundary is January. 'YEAR.2' sets the
boundary at February.

The shift period must be less than or equal to the number of shift-periods in that interval or multiple intervals. For
example 'YEAR.12' is valid, but 'YEAR.13' is not, because the maximum number of shift-periods (months) in a single
year is 12. Likewise the maximum shift-period for one WEEK is seven days, so WEEK.7 is valid, but WEEK.10 is not.

In many cases the shift-period for an interval will be a smaller interval, For example when the interval YEAR the shift-
period is month. Sometimes the shift-period will be the same as the interval. For instance, because week boundaries do
not follow month boundaries, when the Interval is MONTH, the shift-period is also Month. The same is true when the
interval is DAY, but for a different reason. In a SAS Date value the smallest unit that can be represented is a Day.
Below is a list of intervals and shift-periods used in shifting boundaries.

Catagory Interval Shift period

Date YEAR Month


SEMIYEAR Month
QTR Month
MONTH Month
SEMIMONTH Semimonth
TENDAY Tenday
WEEKDAY Day
WEEK Day
DAY Day
Time HOUR Hour
MINUTE Minute
SECOND Second
DateTime *Add DT to any of the above*
*See note below *

Single-Unit and Multiunit Intervals

The difference between single and multi unit intervals is that the default multiplier of 1 is replaced with a larger
number. All the logic is the same. The number of shift-periods available is now the number of shift-periods in the
Interval multiplied by the multiplier. To expand on a sample above, YEAR.13 is not valid because there are only 12
shift-periods (months) in 1 year, however, YEAR2.13 is valid because there are 24 months in a 2 year period. This
would make the boundary January of year 2, 4, 6 and so on. Likewise WEEK.10 is not valid because there are only 7
shift-periods (days) in a week. WEEK2.10 is valid because there are 14 shift-periods. WEEK2.10 would be Tuesday of
TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

week 2, 4, 6, etc.

Suppose you want to use a one year interval, but you are dealing with a fiscal year that starts October 01, you will want
to shift the year to the tenth month. In this example you would specify an interval of 'YEAR.10'.

Now suppose that you want to define an interval that will start on the November 01 of every third year. Perhaps this is
the election date for officers in an organization. You can represent that this way: 'YEAR3.35'.

As stated before, months are handled differently. When using the interval MONTH, the shift-period is the same as the
interval. In other words, if you specify a period as MONTH3.2 the interval is set at 3 months based on the calendar
year with the boundary being the first day of the second month. Below is a sample program and the output that shows
the effect of shifting multiunit intervals. It uses a three month period shifted to the first day of the second subunit
(month). Remember that the INTNX function uses the interval boundary (first argument) to align the date (second
argument) forward or back by the number of intervals (third argument). Also remember that specifying 0 as the number
of intervals returns the starting day of the interval of which the date is a part.

0001 data _null_;


0002 format default=mmddyy10.;
0003 d1=intnx('month3.2','15jan2000'd,0);
0004 d2=intnx('month3.2','15feb2000'd,0);
0005 d3=intnx('month3.2','15jan2000'd,1);
0006 d4=intnx('month3.2','15feb2000'd,1);
0007 put d1= / d2= / d3= / d4= ;
0008 run;

d1=11/01/1999
d2=02/01/2000
d3=02/01/2000
d4=05/01/2000

Normally with a three month interval, the boundaries are the first day of January, April, July, and October. The interval
specified above shifts the interval boundaries to the first of February, May, August, and November.

● D1 starting from January 15, 2000 is adjusted to the beginning of the interval running from November 01, 1999
to January 31, 2000 since this is the shifted interval that contains the starting date.
● D2 starting from February 15, 2000. is adjusted to the beginning of the interval that runs from February 01,
2000 to April 30, 2000 since this is the shifted interval that contains the starting date.
● D3 starting from January 15, 2000, is adjusted forward 1 shifted interval to February 01, 2000.
● D4 starting from February 15, 2000, is adjusted forward 1 shifted interval to May 01, 2000.

Here is another example dealing with single and multiweek normal and shifted intervals. All calculations start from
January 17, 2001. Shifted boundaries are moved to the fourth day or shift-period:

0001 data _null_;


0002 format default=mmddyy10.;
0003 d1=intnx('week1.1','17jan2001'd,0);
0004 d2=intnx('week1.4','17jan2001'd,0);
0005 d3=intnx('week1.1','17jan2001'd,1);
0006 d4=intnx('week1.4','17jan2001'd,1);
0007 put d1= / d2= / d3= / d4= /;
TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

0008 run;

d1=01/14/2001
d2=01/17/2001
d3=01/21/2001
d4=01/24/2001

● D1 The normal boundary for the one-week interval containing 17jan2001.


● D2 is D1 shifted to the fourth day of the week
● D3 The normal boundary for one-week interval starting one week after 17jan2001.
● D4 is D3 shifted to the fourth day of the week.

All the following examples start from January 17, 2001. The normal two week periods around that starting date have
boundary dates of December 31, 2000, January 14, 2001, January 28, 2001, and February 11, 2001. Shifting the two
week periods by 5 days makes the above boundaries January 04, 2001, January 18, 2001, February 01, 2001, and
February 15, 2001.

0001 data _null_;


0002 format default=mmddyy10.;
0003 dd1=intnx('week2.1','17jan2001'd,0);
0004 dd2=intnx('week2.5','17jan2001'd,0);
0005 dd3=intnx('week2.1','17jan2001'd,1);
0006 dd4=intnx('week2.5','17jan2001'd,1);
0007 dd5=intnx('week2.1','17jan2001'd,2);
0008 dd6=intnx('week2.5','17jan2001'd,2);
0009 put dd1= / dd2= / dd3= / dd4= / dd5= / dd6= /;
0010 run;

dd1=01/14/2001
dd2=01/04/2001
dd3=01/28/2001
dd4=01/18/2001
dd5=02/11/2001
dd6=02/01/2001

● DD1 Boundary date for two week period containing start date.
● DD2 The shifted boundaries are used, so the start date now falls in the period from 04jan2001 to 17jan2001. The
date returned is the first day of the two week period.
● DD3 Boundary date for two week period following the two week period containing start date.
● DD4 Using the shifted boundaries, the date returned is the beginning of the next interval.
● DD5 The date returned is two, two week intervals forward from the start date.
● DD6 Using the shifted intervals, the date returned is the boundary, two intervals in the future from the shifted
interval that the start date fell in.

The important thing to remember in using shifted intervals is that the interval boundary is shifted BEFORE the starting
date is examined.

Dealing with multi year intervals

In one of the examples above, I made reference to a three year period that had it's boundary on November 01 of the
third year. The example used 'YEAR3.35'. This will work correctly if your unshifted three year intervals include
TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

January 01, 1960. But if your organization was founded on January 01 1961, with the first election to be held on
November 01, 1961, then every three years after that, you will need to do things just a little differently.

In this case, instead of using 35 to go to November of the third year, which would be November 01 of 1959 then 1962,
you can use a multiunit shifted interval of 'YEAR3.23'. This will ruturn dates of November 01, 1961, 1964 and every
thrid year after that.

Counting weekdays

One of the most frequently asked questions of SAS Technical Support regards counting weekdays within a period of
time. On the surface, INTCK using the WEEKDAY interval looks like the perfect solution. If the period of time you
are measuring weekdays within begins on a Sunday, this is true. If not, then the starting day is missed because the
starting day is not counted. Look at the INTCK function call below:

intck('weekday','03jan2001'd,'04jan2001'd);

When you look at it you see that there are two weekdays if you include the start date in the calculation. However, since
SAS only counts the number of boundaries crossed, the starting date is not counted, so SAS returns a value that is 1 less
than you expect. This issue does not show up if the start date falls on a Saturday or Sunday, because they are not
weekdays and would not be counted anyway.

Getting what you want

You have to examine the starting day and see if it is a weekday. If it is then you need to back up the starting day by
one, so that you can cross the boundary into the starting day causing SAS to count it. The WEEKDAY function can
give you this information. Below is the SAS Log from a program that calculates the number of work days(holidays are
ignored) for each month in 2001. It incorporates much of what has been discussed above. One new technique is in line
0004 below.

Finding the last day of a month seems troublesome, but really is not. Use the INTNX function to advance a SAS Date
to the first of the month following the month you want the last day of, then subtract 1 from the calculated date.
Remember that SAS dates are integer values, so the last day of a given month is just 1 less than the first of the next
month. Since the default boundary of the MONTH interval is the first of the month, this will work everytime. The rest
of the example is ordinary DATA step programming.

0001 data _null_;


0002 do i = 0 to 11;
0003 start=intnx('month','01jan2001'd,i);
0004 end=(intnx('month','01feb2001'd,i))-1;
0005 if 1 < weekday(start) < 7 then startx=start-1;
0006 else startx=start;
0007 count=intck('weekday',startx,end);
0008 put 'In the month of ' start monyy7. ', there are ' count 'weekdays.';
0009 end;
0010 run;

In the month of JAN2001, there are 23 weekdays.


In the month of FEB2001, there are 20 weekdays.
In the month of MAR2001, there are 22 weekdays.
In the month of APR2001, there are 21 weekdays.
In the month of MAY2001, there are 23 weekdays.
TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions

In the month of JUN2001, there are 21 weekdays.


In the month of JUL2001, there are 22 weekdays.
In the month of AUG2001, there are 23 weekdays.
In the month of SEP2001, there are 20 weekdays.
In the month of OCT2001, there are 23 weekdays.
In the month of NOV2001, there are 22 weekdays.
In the month of DEC2001, there are 21 weekdays.

Conclusion

Hopefully this paper has given you insight and understanding into how SAS measures and uses time and time intervals.
For more information see the SAS Language Reference: Dictionary, Version 8 and the SAS Language Reference:
Concepts, Version 8. Both are available in on-line documentation or as bound book form.

Search | Contact Us | Terms of Use & Legal Information | Privacy Statement


Copyright © 2003 SAS Institute Inc. All Rights Reserved.