Académique Documents
Professionnel Documents
Culture Documents
TS Home | Intro to Services | News and Info | Contact TS | Site Map | FAQ | Feedback
TS-668
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.
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'
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
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
Date units
Datetime units
TS-DOC: TS-668 - SAS Dates, Times, and Interval Functions
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);
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
Multiunit Intervals
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;
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:
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:
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.
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.
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.
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:
0008 run;
d1=01/14/2001
d2=01/17/2001
d3=01/21/2001
d4=01/24/2001
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.
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.
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.
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.
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.