Lesson 22: Date and Time Processing
Lesson 22: Date and Time ProcessingOverview
In this lesson, we will investigate various aspects of processing dates and times within the SAS System. Specifically, we will learn:
- how SAS defines numeric date and time values
- how to use informats to read dates and times into a SAS data set
- how to use formats to display SAS dates and times
- how to use dates and times in calculations
- how to compare a SAS date to some date constant, and how to compare a SAS time to some time constant
- how to use several of the available SAS date and time functions
- how to change the system options that pertain to processing date and times
As always, you'll probably want to follow along in the lesson by downloading and running the provided SAS programs yourself.
Objectives
Upon completing this lesson, you should be able to do the following:
- understand how SAS determines the numeric value that it stores for dates, times, and datetimes
- use the appropriate informat in conjunction with an INPUT statement to read in a date, time, and/or datetime value
- use the appropriate format in conjunction with a FORMAT statement to display a date, time, and/or datetime value
- understand the importance of the width specification in a date informat or format
- use date variables in basic arithmetic calculations
- write any date as a SAS date constant and any time as a SAS time constant
- know how each of the SAS date functions that we investigate in the lesson work
- know how SAS defines a Julian date
- understand the effect of the various suffices that you can attach to mmddyy, ddmmyy, etc. formats
- know how to use the various date and time informats and formats available in SAS
- know what the DATESTYLE= system option does
- know what the YEARCUTOFF= system option does
- know how each of the SAS time functions that we investigate in the lesson work
22.1 - SAS Date Basics
22.1 - SAS Date BasicsIn this section, we'll get a quick and broad overview of the fundamental things you need to know about working with dates in SAS. We'll learn how SAS defines a date value, how to use an informat to read a date into a SAS data set, how to use a format to display a SAS date, how to perform simple date calculations, and how to define a SAS date constant.
The Definition of a SAS Date
SAS stores dates as single, unique numbers, so that they can be used in your programs like any other numeric value. Specifically, SAS stores dates as numeric values equal to the number of days from January 1, 1960. That is, dates prior to January 1, 1960 are stored as unique negative integers, and dates after January 1, 1960 are stored as unique positive integers. So, for example, SAS stores:
- a 0 for January 1, 1960
- a 1 for January 2, 1960
- a 2 for January 3, 1960
- and so on ...
And, SAS stores:
- a -1 for December 31, 1959
- a -2 for December 30, 1959
- a -3 for December 29, 1959
- and so on ...
No matter what method is used in creating a SAS date, SAS always converts the date to an integer as just defined.
Using an Informat to Read in a SAS Date
As you already know, in order to read variables that are dates, we need to tell SAS what form the date takes. For example, is the date in the form Dec 1, 2005? Or is it 12/01/05? Or 01 December 2005? The form that a date takes on input is known as a date informat. There seems to be as much SAS date informats as there are ways that you could imagine writing a date. Well, okay, maybe not quite that many. We'll take a look at several of the informats that are available in SAS later in this lesson. For now, we'll just refresh our memory of how to write the formatted style input statement that is necessary to read in dates.
Example 22.1.
The following SAS program reads five observations into a SAS data set called diet. Two of the variables — weight date (wt_date) and birth date (b_date) — are in mm/dd/yy format, and therefore SAS is told to read the dates using the mmddyy8. informat:
DATA diet;
input subj 1-4 l_name $ 18-23 weight 30-32
+1 wt_date mmddyy8. @43 b_date mmddyy8.;
DATALINES;
1024 Alice Smith 1 65 125 12/1/05 01/01/60
1167 Maryann White 1 68 140 12/01/05 01/01/59
1168 Thomas Jones 2 190 12/2/05 06/15/60
1201 Benedictine Arnold 2 68 190 11/30/05 12/31/60
1302 Felicia Ho 1 63 115 1/1/06 06/15/58
;
RUN;
PROC PRINT data=diet;
TITLE 'The unformatted diet data set';
RUN;
Obs | subj | l_name | weight | wt_date | b_date |
---|---|---|---|---|---|
1 | 1024 | Smith | 125 | 16771 | 0 |
2 | 1167 | White | 140 | 16771 | -365 |
3 | 1168 | Jones | 190 | 16772 | 166 |
4 | 1201 | Arnold | 190 | 16770 | 365 |
5 | 1302 | Ho | 115 | 16802 | -565 |
First, note that the mmddyy8. informat must immediately follow the date's variable name. Here, it immediately follows wt_date, and then again follows b_date. Incidentally, the 8 in mmddyy8. defines, in general, the width of the informat. It tells SAS that the dates to be read into SAS contain as many as 8 positions. Here, two of the positions are taken up by forward slashes (/). You could alternatively use hyphens (-) or blank spaces between the mm dd and yy. Also, note that the period is a very important part of the informat name. Without it, SAS may attempt to interpret the informat as a variable name instead.
Then, launch and run the SAS program, and review the resulting output to familiarize yourself with the contents of the diet data set. Note, in particular, the numeric values that are stored for the wt_date and b_date variables. As expected, the 01/01/60 birth date is stored as a 0, the 01/01/59 birthdate is stored as -365, and the 12/31/60 birthdate is stored as +365. Well, I guess the other thing that the output illustrates is that it is not enough just to tell SAS what informat to use to read in a date's value, you also have to tell SAS what format to use to display a date's value. If you don't, as you see here, the dates that are displayed are not particularly user-friendly!
Using a Format to Display a SAS Date
As the preceding example illustrates, we have to tell SAS in what form we would like our dates displayed. The form that a date takes in output is known as a date format. Do we want the date displayed in the form Dec 1, 2005? Or 12/01/05? Or 01 December 2005? Again, there seem to be as many SAS date formats as there are ways that you could imagine writing a date. To tell SAS in which form we want our dates displayed, we use a FORMAT statement.
Example 22.2.
The following SAS program is identical to the previous program, except a FORMAT statement has been added to tell SAS to display the wt_date and b_date variables in date7. format:
DATA diet;
input subj 1-4 l_name $ 18-23 weight 30-32
+1 wt_date mmddyy8. @43 b_date mmddyy8.;
format wt_date b_date date7.;
DATALINES;
1024 Alice Smith 1 65 125 12/1/05 01/01/60
1167 Maryann White 1 68 140 12/01/05 01/01/59
1168 Thomas Jones 2 190 12/2/05 06/15/60
1201 Benedictine Arnold 2 68 190 11/30/05 12/31/60
1302 Felicia Ho 1 63 115 1/1/06 06/15/58
;
RUN;
PROC PRINT data=diet;
title 'The formatted diet data set';
RUN;
Obs | subj | l_name | weight | wt_date | b_date |
---|---|---|---|---|---|
1 | 1024 | Smith | 125 | 01DEC05 | 01JAN60 |
2 | 1167 | White | 140 | 01DEC05 | 01JAN59 |
3 | 1168 | Jones | 190 | 02DEC05 | 15JUN60 |
4 | 1201 | Arnold | 190 | 30NOV05 | 31DEC60 |
5 | 1302 | Ho | 115 | 01JAN06 | 15JUN58 |
First, take note of the FORMAT statement in which the selected format date7. follows the two variables — wt_date and b_date — whose values we want to display as ddMonyy. Then, launch and run the SAS program, and review the resulting output to convince yourself of the effect of the FORMAT statement.
Using SAS Dates in Calculations
The best thing about SAS dates is that, because SAS date values are numeric values, you can easily sort them, subtract them, and add them. You can also compare dates. Or, you can use them in many of the available numeric functions.
Example 22.3
The following SAS program illustrates how you can treat date variables as any other numeric variable, and therefore can use the dates in numeric calculations. Assuming that individuals in the diet data set need to be weighed every 14 days, a new variable nxt_date, the anticipated date of the individual's next visit, is determined by merely adding 14 to the individual's current weight date (wt_date). Then, a crude estimate of each individual's age is also calculated by subtracting b_date from wt_date and dividing the resulting number of days by 365.25 to get an approximate age in years. And, the MEAN function is used to calculate avg_date, the average of each individual's birth and weight dates:
DATA diet;
input subj 1-4 l_name $ 18-23 weight 30-32
+1 wt_date mmddyy8. @43 b_date mmddyy8.;
nxt_date = wt_date + 14;
age_wt = (wt_date - b_date)/365.25;
avg_date = MEAN(wt_date, b_date);
format wt_date b_date nxt_date avg_date date7.
age_wt 4.1;
DATALINES;
1024 Alice Smith 1 65 125 12/1/05 01/01/60
1167 Maryann White 1 68 140 12/01/05 01/01/59
1168 Thomas Jones 2 190 12/2/05 06/15/60
1201 Benedictine Arnold 2 68 190 11/30/05 12/31/60
1302 Felicia Ho 1 63 115 1/1/06 06/15/58
;
RUN;
PROC PRINT data=diet;
title 'The diet data set with three new variables';
RUN;
Obs | subj | l_name | weight | wt_date | b_date | nxt_date | age_wt | avg_date |
---|---|---|---|---|---|---|---|---|
1 | 1024 | Smith | 125 | 01DEC05 | 01JAN60 | 15DEC05 | 45.9 | 16DEC82 |
2 | 1167 | White | 140 | 01DEC05 | 01JAN59 | 15DEC05 | 46.9 | 17JUN82 |
3 | 1168 | Jones | 190 | 02DEC05 | 15JUN60 | 16DEC05 | 45.5 | 10MAR83 |
4 | 1201 | Arnold | 190 | 30NOV05 | 31DEC60 | 14DEC05 | 44.9 | 16JUN83 |
5 | 1302 | Ho | 115 | 01JAN06 | 15JUN58 | 15JAN06 | 47.5 | 24MAR82 |
First, review the code to see how the three new variables — nxt_date, age_wt, and avg_date — are calculated using standard numeric expressions. You should also acknowledge that the calculation of avg_date is just a desperate attempt by a desperate instructor to illustrate the use of dates in a standard numeric function, and is otherwise probably fairly useless. Then, launch and run the SAS program, and review the resulting output to convince yourself that the results of the calculations seem reasonable.
Example 22.4
The following SAS program illustrates again how you can treat date variables as any other numeric variable, and therefore can sort dates. The diet data set is sorted by nxt_date in ascending order so that the individuals whose next weigh-in date is closest in time appear first:
PROC SORT data = diet out = sorteddiet;
by nxt_date;
RUN;
PROC PRINT data = sorteddiet;
TITLE 'The diet data set sorted by nxt_date';
RUN;
Obs | subj | l_name | weight | wt_date | b_date | nxt_date | age_wt | avg_date |
---|---|---|---|---|---|---|---|---|
1 | 1201 | Arnold | 190 | 30NOV05 | 31DEC60 | 14DEC05 | 44.9 | 16JUN83 |
2 | 1024 | Smith | 125 | 01DEC05 | 01JAN60 | 15DEC05 | 45.9 | 16DEC82 |
3 | 1167 | White | 140 | 01DEC05 | 01JAN59 | 15DEC05 | 46.9 | 17JUN82 |
4 | 1168 | Jones | 190 | 02DEC05 | 15JUN60 | 16DEC05 | 45.5 | 10MAR83 |
5 | 1302 | Ho | 115 | 01JAN06 | 15JUN58 | 15JAN06 | 47.5 | 24MAR82 |
First, review the code, and then launch and run the SAS program. Then, review the resulting output to convince yourself that the variable nxt_date is sorted as indeed claimed.
Comparing Dates
Again, because SAS date values are numeric values, you can easily compare two or more dates. The comparisons are made just as the comparisons between any two numbers would take place. For example, because the date 01/03/60 is stored as a 2 in SAS, it is considered smaller than the date 01/10/60, which is stored as a 9 in SAS.
Example 22.5.
The following SAS program illustrates how to compare the values of a date variable, not to the values of some other date variable, but rather to a date constant. Specifically, the WHERE= option that appears on the DATA statement tells SAS to output to the diet data set only those individuals whose b_date is before January 1, 1960:
DATA diet (where = (b_date < '01jan1960'd));
input subj 1-4 l_name $ 18-23 weight 30-32
+1 wt_date mmddyy8. @43 b_date mmddyy8.;
format wt_date b_date date9.;
DATALINES;
1024 Alice Smith 1 65 125 12/1/05 01/01/60
1167 Maryann White 1 68 140 12/01/05 01/01/59
1168 Thomas Jones 2 190 12/2/05 06/15/60
1201 Benedictine Arnold 2 68 190 11/30/05 12/31/60
1302 Felicia Ho 1 63 115 1/1/06 06/15/58
;
RUN;
PROC PRINT data=diet;
title 'Birthdays in the diet data set before 01/01/1960';
RUN;
Obs | subj | l_name | weight | wt_date | b_date |
---|---|---|---|---|---|
1 | 1167 | White | 140 | 01DEC2005 | 01JAN1959 |
2 | 1302 | Ho | 115 | 01JAN2006 | 15JUN1958 |
First, note the form of the SAS date constant:
'01jan1960'd
used in the WHERE= option. In general, a SAS date constant takes the form 'ddMONyyyy'd where dd denotes the day of the month (0, ..., 31), MON denotes the first three letters of the month, and yyyy denotes the four-digit year. The letter d that follows the date in single quotes tells SAS to treat the date string like a constant. Note that regardless of how you have informatted or formatted your SAS dates, the SAS date constant always takes the above form.
Now, launch and run the SAS program. Then, review the resulting output to convince yourself that only those individuals whose birth date is before January 1, 1960, are included in the output diet data set. You might also want to note the difference between the date7. and date9. format. Previously, we saw that when you used the date7. format, your dates are displayed in ddMonyy format. Here, you can see that when you use the date9. format, your dates are displayed in ddMonyyyy format. (Incidentally, I think it is a good practice to use four-digit years wherever possible to avoid any ambiguity.) We'll take a look at some of the other informats and formats available later in this lesson. Now, we'll go take a look at some of the available functions that work specifically with SAS dates.
22.2 - SAS Date Functions
22.2 - SAS Date FunctionsThe date functions that are available in SAS can be used to:
- create date values
- take apart date values
- massage date values (what??!)
- calculate intervals
For no particular reason, we'll look at them in that order.
Using functions to create date values
The functions that can be used to create date values include:
- date( ) returns today's date as a SAS date value
- today( ) returns today's date as a SAS date value
- mdy(m,d,y) returns a SAS date value from the given month (m), day (d), and year (y) values
- datejul(juldate) converts a Julian date (juldate) to a SAS date value
- yyq(y, q) returns a SAS date value from the given year (y) and quarter (q) 1, 2, 3, or 4
The date( ) and today( ) functions are equivalent. That is, they both return the current date as defined as the date on which the SAS program is executed. You don't need to put anything in between the parentheses for those two functions.
A Julian date is defined in SAS as a date in the form yyddd or yyyyddd, where yy or yyyy is a two-digit or four-digit integer that represents the year, and ddd is the number of the day of the year. The value of ddd must be between 001 and 365 (or 366 for a leap year). So, for example, the SAS Julian date for January 21, 2008 is 2008021.
Let's look at an example in which these five functions are used.
Example 22.6
The following SAS program creates a temporary SAS data set called createdates that contains six date variables. The variables current1 and current2 are assigned the current date using the date( )and today( ) functions. The variable current3 is assigned the 95th day of the 2008 year using the datejul( ) function. The variables current4 and current5 are assigned the date April 4th, 2008 using the mdy( ) function. And, the variable current6 is assigned the date April 1st, 2008 using the yyq( ) function.
DATA createdates;
current1= date();
current2 = today();
current3 = datejul(2008095);
mon = 4; day = 4; year = 2008;
current4 = mdy(mon, day, year);
current5 = current4;
current6 = yyq(2008, 2);
format current1 current2 current3 current5 current6 date9.;
RUN;
PROC PRINT data=createdates;
title 'The createdates data set';
var current1 current2 current3 current4 current5 current6;
RUN;
Obs | current1 | current2 | current3 | current4 | current5 | current6 |
---|---|---|---|---|---|---|
1 | 20SEP2023 | 20SEP2023 | 04APR2008 | 17626 | 04APR2008 | 01APR2008 |
First, review the program to make sure that you understand how to use each of the five functions. Note, for example, that to tell SAS to determine the SAS date value of the 95th day of the 2008 year, you have to input 2008095 into the datejul( ) function. If you instead input 200895 into the datejul( ) function, SAS reports that you've provided an invalid argument to the datejul( ) function and therefore sets current3 to missing. Also, note that current5 is just the formatted version of the unformatted current4 variable. When you are satisfied that you understand the five functions, launch and run the SAS program. Review the output to convince yourself that createdates does indeed contain the six date variables as described.
Using functions to take apart date values
The functions that can be used to take apart date values include:
- day(date) returns the day of the month from a SAS date value (date)
- month(date) returns the month from a SAS date value (date)
- year(date) returns the year from a SAS date value (date)
The date can be specified either as a variable name or as a SAS date constant. Otherwise, fairly self-explanatory! Let's take a look at an example.
Example 22.7
The following SAS program uses the day( ), month( ), and year( ) functions to extract the month, day, and year from the wt_date variable:
DATA takeapart;
input subj 1-4 l_name $ 18-23 weight 30-32
+1 wt_date mmddyy8. @43 b_date mmddyy8.;
wt_mo = month(wt_date);
wt_day = day(wt_date);
wt_yr = year(wt_date);
format wt_date b_date date9.;
DATALINES;
1024 Alice Smith 1 65 125 12/1/05 01/01/60
1167 Maryann White 1 68 140 12/01/05 01/01/59
1168 Thomas Jones 2 190 12/2/05 06/15/60
1201 Benedictine Arnold 2 68 190 11/30/05 12/31/60
1302 Felicia Ho 1 63 115 1/1/06 06/15/58
;
RUN;
PROC PRINT data=takeapart;
title 'The dissected weight dates';
var wt_date wt_mo wt_day wt_yr;
RUN;
Obs | wt_date | wt_mo | wt_day | wt_yr |
---|---|---|---|---|
1 | 01DEC2005 | 12 | 1 | 2005 |
2 | 01DEC2005 | 12 | 1 | 2005 |
3 | 02DEC2005 | 12 | 2 | 2005 |
4 | 30NOV2005 | 11 | 30 | 2005 |
5 | 01JAN2006 | 1 | 1 | 2006 |
First, review the program to make sure that you understand how to use each of the three functions. Then, launch and run the SAS program, and review the output to convince yourself that the program does as claimed.
Using functions to massage date values
Okay, here's that section with the intriguing title. The functions that can be used to massage date values include:
- juldate(date) returns the Julian date in yyddd format from a SAS date value (date)
- juldate7(date) returns the Julian date in yyyyddd format from a SAS date value (date)
- qtr(date) returns the quarter of the year from a SAS date value (date) (1 = first three months, 2 = second three months, 3 = third three months, or 4 = last three months)
- weekday(date) returns the number of the day of the week from a date value (date) (1 = Sunday, 2 = Monday, ..., and 7 = Saturday)
Again, the date can be specified either as a variable name or as a SAS date constant. And, a Julian date in SAS is defined as a date in the form yyddd or yyyyddd, where yy or yyyy is a two-digit or four-digit integer that represents the year and ddd is the number of the day of the year (between 001 and 365 (or 366 for a leap year)).
Let's look at an example in which these four functions are used.
Example 22.8
The following SAS program contains four assignment statements that "massage" the wt_date variable. The variable wt_jul1 is assigned the SAS Julian date in yyddd format. The variable wt_jul2 is assigned the SAS Julian date in yyyyddd format. The variable wt_qtr is assigned the quarter in which the wt_date occurs, and the variable wt_day is assigned the weekday on which the wt_date occurs:
DATA massaged;
input subj 1-4 l_name $ 18-23 weight 30-32
+1 wt_date mmddyy8. @43 b_date mmddyy8.;
wt_jul1 = juldate(wt_date);
wt_jul2 = juldate7(wt_date);
wt_qtr = qtr(wt_date);
wt_day = weekday(wt_date);
format wt_date b_date date9.;
DATALINES;
1024 Alice Smith 1 65 125 12/1/05 01/01/60
1167 Maryann White 1 68 140 12/01/05 01/01/59
1168 Thomas Jones 2 190 12/2/05 06/15/60
1201 Benedictine Arnold 2 68 190 11/30/05 12/31/60
1302 Felicia Ho 1 63 115 1/1/06 06/15/58
;
RUN;
PROC PRINT data = massaged;
title 'The massaged data set';
var wt_date wt_jul1 wt_jul2 wt_qtr wt_day;
RUN;
Obs | wt_date | wt_jul1 | wt_jul2 | wt_qtr | wt_day |
---|---|---|---|---|---|
1 | 01DEC2005 | 5335 | 2005335 | 4 | 5 |
2 | 01DEC2005 | 5335 | 2005335 | 4 | 5 |
3 | 02DEC2005 | 5336 | 2005336 | 4 | 6 |
4 | 30NOV2005 | 5334 | 2005334 | 4 | 4 |
5 | 01JAN2006 | 6001 | 2006001 | 1 | 1 |
First, review the program to make sure that you understand how to use each of the four functions. Then, launch and run the SAS program, and review the output to convince yourself that the program does as claimed.
Using functions to calculate intervals
The functions that can be used to calculate intervals include:
- yrdif(startdate, enddate, 'method') returns the difference in years between two SAS date values (startdate, enddate) using one of four methods ('method')
- datdif(startdate, enddate, 'method') returns the difference in days between two SAS date values (startdate, enddate) using one of four methods ('method')
- intck('interval', fromdate, todate) returns the number of time intervals ('interval') that occur between two dates (fromdate, todate)
- intnx('interval', date, increment) applies multiples (increment) of a given interval ('interval') to a date value (date) and returns the resulting value, and hence can be used to identify past or future days, weeks, months, and so on
We'll take a look at five examples here. The first one uses the yrdif( ) and datdif( ) functions, the next three use the intck( ) function, and the last one uses the intnx( ) function.
Example 22.9
The following SAS program uses the yrdif( ) function to calculate the difference between the subject's birth date (b_date) and first weight date (wt_date1) in order to determine the subject's age. And, the datdif( ) function is used to calculate days, the difference between the subject's first (wt_date1) and second (wt_date2) weight dates:
DATA diet;
input subj 1-4 l_name $ 18-23 weight 30-32
+1 wt_date1 mmddyy8. @43 wt_date2 mmddyy8. @52
b_date mmddyy8.;
age = yrdif(b_date, wt_date1, 'act/act');
days = datdif(wt_date1, wt_date2, 'act/act');
format wt_date1 wt_date2 b_date date9. age 4.1;
DATALINES;
1024 Alice Smith 1 65 125 12/1/05 03/04/06 01/01/60
1167 Maryann White 1 68 140 12/01/05 03/07/06 01/01/59
1168 Thomas Jones 2 190 12/2/05 3/30/06 06/15/60
1201 Benedictine Arnold 2 68 190 11/30/05 2/27/06 12/31/60
1302 Felicia Ho 1 63 115 1/1/06 4/1/06 06/15/58
;
RUN;
PROC PRINT data=diet;
TITLE "The calculation of subject's age";
var subj b_date wt_date1 age;
RUN;
PROC PRINT data=diet;
TITLE 'The calculation of days between weighings';
var subj wt_date1 wt_date2 days;
RUN;
Obs | subj | b_date | wt_date1 | age |
---|---|---|---|---|
1 | 1024 | 01JAN1960 | 01DEC2005 | 45.9 |
2 | 1167 | 01JAN1959 | 01DEC2005 | 46.9 |
3 | 1168 | 15JUN1960 | 02DEC2005 | 45.5 |
4 | 1201 | 31DEC1960 | 30NOV2005 | 44.9 |
5 | 1302 | 15JUN1958 | 01JAN2006 | 47.5 |
Obs | subj | wt_date1 | wt_date2 | days |
---|---|---|---|---|
1 | 1024 | 01DEC2005 | 04MAR2006 | 93 |
2 | 1167 | 01DEC2005 | 07MAR2006 | 96 |
3 | 1168 | 02DEC2005 | 30MAR2006 | 118 |
4 | 1201 | 30NOV2005 | 27FEB2006 | 89 |
5 | 1302 | 01JAN2006 | 01APR2006 | 90 |
Review the assignment statement that is used to calculate the values for the variable age. The first and second arguments of the yrdif( ) function tell SAS, respectively, the start and end date of the desired interval. Here, the start date is b_date and the end date is wt_date1. The third argument of the yrdif( ) function, which must be enclosed in single quotes, tells SAS how to calculate the difference. Here, 'act/act' tells SAS to calculate the difference using the actual number of years between the two dates. The four possible methods in calculating the number of years between two dates using the yrdif( ) function are:
- 'act/act' uses the actual number of days and years between two dates
- '30/360' specifies a 30-day month and a 360-day year
- 'act/360' uses the actual number of days between dates in calculating the number of years (calculated by the number of days divided by 360)
- 'act/365' uses the actual number of days between dates in calculating the number of years (calculated by the number of days divided by 365)
The 'act/act' method is the method that most people would consider to be the most accurate. The other methods are methods that are sometimes used by accountants.
Now, review the assignment statement that is used to calculate the values for the variable days. The first and second arguments of the datdif( ) function tell SAS, respectively, the start and end date of the desired interval. Here, the start date is wt_date1 and the end date is wt_date2. The third argument of the datdif( ) function, which must be enclosed in single quotes, tells SAS how to calculate the difference. Here, 'act/act' tells SAS to calculate the difference using the actual number of days between the two dates. The two possible methods for calculating the number of days between two dates using the datdif( ) function are:
- 'act/act' uses the actual number of days and years between two dates
- '30/360' specifies a 30-day month and a 360-day year
Again, the 'act/act' method is the method that most people would consider to be the most accurate. The other method is a method that is sometimes used by accountants.
When you are satisfied that you understand the two functions, launch and run the SAS program. Review the output to convince yourself that age and days are indeed calculated as described.
Example 22.10
Recall that the intck( ) function returns the number of time intervals, such as the number of days or years, that occur between two dates. The following SAS program is identical to the previous program, except here the subjects' ages at their first weigh-in are determined using both the yrdif( ) and intck( ) functions to get age_yrdif and age_intchk, respectively. Similarly, the number of days between the subjects' two weigh-ins is determined using both the datdif( ) and intck( ) functions to get days_datdif and days_intchk, respectively:
DATA diet;
input subj 1-4 l_name $ 18-23 weight 30-32
+1 wt_date1 mmddyy8. @43 wt_date2 mmddyy8. @52
b_date mmddyy8.;
age_yrdif = yrdif(b_date, wt_date1, 'act/act');
age_intck = intck('year', b_date, wt_date1);
days_datdif = datdif(wt_date1, wt_date2, 'act/act');
days_intck = intck('day', wt_date1, wt_date2);
format wt_date1 wt_date2 b_date date9. age 4.1;
DATALINES;
1024 Alice Smith 1 65 125 12/1/05 03/04/06 01/01/60
1167 Maryann White 1 68 140 12/01/05 03/07/06 01/01/59
1168 Thomas Jones 2 190 12/2/05 3/30/06 06/15/60
1201 Benedictine Arnold 2 68 190 11/30/05 2/27/06 12/31/60
1302 Felicia Ho 1 63 115 1/1/06 4/1/06 06/15/58
;
RUN;
PROC PRINT data=diet;
TITLE "The calculation of subject's age";
var subj b_date wt_date1 age_yrdif age_intck;
RUN;
PROC PRINT data=diet;
TITLE 'The calculation of days between weighings';
var subj wt_date1 wt_date2 days_datdif days_intck;
RUN;
Obs | subj | b_date | wt_date1 | age_yrdif | age_intck |
---|---|---|---|---|---|
1 | 1024 | 01JAN1960 | 01DEC2005 | 45.9151 | 45 |
2 | 1167 | 01JAN1959 | 01DEC2005 | 46.9151 | 46 |
3 | 1168 | 15JUN1960 | 02DEC2005 | 45.4643 | 45 |
4 | 1201 | 31DEC1960 | 30NOV2005 | 44.9151 | 45 |
5 | 1302 | 15JUN1958 | 01JAN2006 | 47.5479 | 48 |
Obs | subj | wt_date1 | wt_date2 | days_datdif | days_intck |
---|---|---|---|---|---|
1 | 1024 | 01DEC2005 | 04MAR2006 | 93 | 93 |
2 | 1167 | 01DEC2005 | 07MAR2006 | 96 | 96 |
3 | 1168 | 02DEC2005 | 30MAR2006 | 118 | 118 |
4 | 1201 | 30NOV2005 | 27FEB2006 | 89 | 89 |
5 | 1302 | 01JAN2006 | 01APR2006 | 90 | 90 |
Review the assignment statement that is used to calculate the values for the variable age_intck. The first argument of the intck( ) function, which must appear in single quotes, tells SAS what time interval you are interested in counting. Although there are other intervals available, the most commonly used intervals include 'day', 'weekday', 'week', 'month', 'qtr', and 'year'. The second and third arguments of the intck( ) function tell SAS, respectively, the start and end date of the desired interval. Here, the start date is b_date, the end date is wt_date1, and the time interval is 'year'.
Now, review the assignment statement that is used to calculate the values for the variable days_intck. To calculate days, the start date is wt_date1, the end date is wt_date2, and the time interval is 'day'.
Theoretically, we should expect the yrdif( ) and intck( ) functions to get the same answers for age, and the datdif( ) and intck( ) functions to get the same answers for days. Launch and run the SAS program, and review the resulting output. Same answers or not? Hmmm ... you should see that the values for days_datdif and days_intck are the same, while the (rounded) values for age_yrdif and age_intck differ.
Why is that the case? It has to do with the fact that the intck( ) function counts intervals from fixed interval beginnings, not in multiples of an interval unit from the startdate value. Partial intervals are not counted. For example, 'week' intervals are counted by Sundays rather than seven-day multiples from the startdate value. 'Month' intervals are counted by the first day of each month, and 'year' intervals are counted from January 1st, not in 365-day multiples from the startdate value.
The next two examples are intended to help you understand how the intck( ) function counts intervals.
Example 22.11
The following SAS program uses the intck( ) function and SAS date constants to determine the number of days, weeks, months, and years between December 31, 2006, and January 1, 2007. It also calculates the number of years (years2) between January 1, 2007 and December 31, 2007, and the number of years (years3) between January 1, 2007 and January 1, 2008:
DATA timeintervals1;
days = intck('day', '31dec2006'd,'01jan2007'd);
weeks = intck('week', '31dec2006'd,'01jan2007'd);
months = intck('month', '31dec2006'd,'01jan2007'd);
years = intck('year', '31dec2006'd,'01jan2007'd);
years2 = intck('year', '01jan2007'd, '31dec2007'd);
years3 = intck('year', '01jan2007'd, '01jan2008'd);
RUN;
PROC PRINT data = timeintervals1;
TITLE 'Time intervals as calculated by intck function';
RUN;
Obs | days | weeks | months | years | years2 | years3 |
---|---|---|---|---|---|---|
1 | 1 | 0 | 1 | 1 | 0 | 1 |
First, review the program to make sure that you understand what it is doing. Then, launch and run the SAS program, and review the output. Are you surprised by any of the results? Let me venture to suggest that you find the results for days, weeks, and years3 to make sense, and the results for months, years, and years2 to be a little odd. Let's focus on the three odd results. In spite of only one day passing between 12/31/2006 and 01/01/2007, SAS assigns the variable months the value 1 because, between 12/31/2006 and 01/01/2007, exactly one first day of the month is crossed (which happens to be January 1st). Similarly, in spite of only one day passing between 12/31/2006 and 01/01/2007, SAS assigns the variable years the value 1 because, between 12/31/2006 and 01/01/2007, exactly one January 1st is crossed. And, in spite of 364 days passing between 01/01/2007 and 12/31/2007, SAS assigns the variable years2 the value 0 because no January 1st is crossed. Now, even though the results for days, weeks, and years3 might make intuitive sense to you, you should still make sure you understand why SAS assigns the values it does here based on how the intck( ) function works.
Example 22.12
In an attempt to explore the intck( ) function further, the following SAS program uses the intck( ) function and SAS date constants to determine the number of days, weeks, weekdays, months, qtrs, and years between March 15, 2007 and March 15, 2008:
DATA timeintervals2;
days = intck('day', '15mar2007'd,'15mar2008'd);
weeks = intck('week', '15mar2007'd,'15mar2008'd);
weekdays = intck('weekday', '15mar2007'd,'15mar2008'd);
months = intck('month', '15mar2007'd,'15mar2008'd);
qtrs = intck('qtr', '15mar2007'd,'15mar2008'd);
years = intck('year', '15mar2007'd,'15mar2008'd);
RUN;
PROC PRINT data = timeintervals2;
TITLE 'Time intervals as calculated by intck function';
RUN;
Obs | days | weeks | weekdays | months | qtrs | years |
---|---|---|---|---|---|---|
1 | 366 | 52 | 261 | 12 | 4 | 1 |
The main purpose of this program is to illustrate some of the intervals most commonly used in the intck( ) function. First, review the program to make sure that you understand what it is doing. Then, launch and run the SAS program, and review the output. Are you surprised by any of the results? In each case, I think you'll find the results to make intuitive sense.
Example 22.13
Now, suppose that each subject appearing in the diet data set needs to be weighed again in three months. The following SAS program uses the subject's previous weight date (wt_date) and various versions of the intnx( ) function to determine various versions of each subject's next weight date:
DATA diet;
input subj 1-4 l_name $ 18-23 weight 30-32
+1 wt_date mmddyy8. @43 b_date mmddyy8.;
nxdate_b1 = intnx('month', wt_date, 3);
nxdate_b2 = intnx('month', wt_date, 3, 'beginning');
nxdate_m = intnx('month', wt_date, 3, 'middle');
nxdate_e = intnx('month', wt_date, 3, 'end');
nxdate_s = intnx('month', wt_date, 3, 'sameday');
format wt_date b_date nxdate_b1 nxdate_b2
nxdate_m nxdate_e nxdate_s date9.;
DATALINES;
1024 Alice Smith 1 65 125 12/1/05 01/01/60
1167 Maryann White 1 68 140 12/01/05 01/01/59
1168 Thomas Jones 2 190 12/2/05 06/15/60
1201 Benedictine Arnold 2 68 190 11/30/05 12/31/60
1302 Felicia Ho 1 63 115 1/1/06 06/15/58
;
RUN;
PROC PRINT data=diet;
TITLE 'The data set containing next weight dates';
VAR subj wt_date nxdate_b1 nxdate_b2
nxdate_m nxdate_e nxdate_s;
RUN;
Obs | subj | wt_date | nxdate_b1 | nxdate_b2 | nxdate_m | nxdate_e | nxdate_s |
---|---|---|---|---|---|---|---|
1 | 1024 | 01DEC2005 | 01MAR2006 | 01MAR2006 | 16MAR2006 | 31MAR2006 | 01MAR2006 |
2 | 1167 | 01DEC2005 | 01MAR2006 | 01MAR2006 | 16MAR2006 | 31MAR2006 | 01MAR2006 |
3 | 1168 | 02DEC2005 | 01MAR2006 | 01MAR2006 | 16MAR2006 | 31MAR2006 | 02MAR2006 |
4 | 1201 | 30NOV2005 | 01FEB2006 | 01FEB2006 | 14FEB2006 | 28FEB2006 | 28FEB2006 |
5 | 1302 | 01JAN2006 | 01APR2006 | 01APR2006 | 15APR2006 | 30APR2006 | 01APR2006 |
Let's review the five assignment statements that calculate five versions of the subjects' next weight dates (nxdate_b1, nxdate_b2, nxdate_m, nxdate_e, and nxdate_s). As you can see, SAS is told to use the 'month' interval in each of the calculations. Again, although there are other intervals available, the most commonly used intervals include 'day', 'weekday', 'week', 'month', 'qtr', and 'year'. SAS is also told to use wt_date as the startdate in each of the calculations. And in each case, SAS is told to advance the wt_date by 3 months. Okay, so the only thing that differs between the five calculations are the last (optional) arguments ('beginning', 'middle', 'end', and 'sameday'). These so-called alignment arguments tell SAS to return either the beginning, middle, or end day of the resulting month. If an alignment is not specified, the beginning day is returned by default. If the 'sameday' alignment is specified, SAS of course returns the same number day but shifted by the number of specified intervals.
Let's launch and run the SAS program, and review the output. The dates should be as described. The contents of nxdate_b1 is the same as nxdate_b2, since the beginning day is returned by default. The variable nxdate_m contains the middle day of the resulting month, and nxdate_e contains the end day of the resulting month. And, for four of the subjects, SAS returns the same number day but 3 months in the future. For subject #1201, you would expect SAS to return February 30th, because it is exactly 3 months from November 30th. This illustrates how the intnx( ) function automatically adjusts the date if the resulting date doesn't exist.
Whewww! That does it! Everything you wanted to know about SAS date functions and more. Let's move on and touch a little bit more on reading and displaying dates in SAS.
22.3 - SAS Date Informats and Formats
22.3 - SAS Date Informats and FormatsThroughout this lesson so far, we have used the mmddyy8. informat to read in SAS dates. And, we have used the date7. and date9. formats to display SAS dates. In this section, we'll just take a look at a few quick examples to illustrate some of the other informats and formats available in SAS.
Example 22.14
The following SAS program reads in three dates (date1, date2, and date3) using a mmddyy informat. Then, the dates are printed using a ddmmyy format:
DATA inputdates1;
INPUT @6 date1 mmddyy6. @13 date2 mmddyy8. @22 date3 mmddyy10.;
FORMAT date1 ddmmyy10. date2 ddmmyyb10. date3 ddmmyyc10.;
DATALINES;
041008 04-10-08 04 10 2008
;
RUN;
PROC PRINT data = inputdates1;
TITLE 'The mmddyy informat and the ddmmyy format';
RUN;
Obs | date1 | date2 | date3 |
---|---|---|---|
1 | 10/04/2008 | 10 04 2008 | 10:04:2008 |
First, review the INPUT statement and the corresponding forms of the April 10, 2008 date in the DATALINES statement. Note, in particular, that the width of the mmddyy informat (6, 8, or 10) tells SAS what form of the date it should expect. Don't worry — SAS will let you know if you misspecify the width of the format! Also, note that the way that we format dates can be completely independent of the way that they are informatted. Here, the dates are read in using the mmddyy informat and are displayed in the rearranged ddmmyy format. Well, let's be a little more specific here about that ddmmyy format. The "b" that appears in the format for the date2 variable tells SAS to display blank spaces between the month, day, and year. The "c" that appears in the format for the date3 variable tells SAS to display colons between the month, day, and year. If nothing appears (or alternatively an "s") in a ddmmyy format, as it does here for the date1 variable, SAS will display forward slashes between the month, day, and year.
When you are satisfied you understand the use of the mmddyy informat and the ddmmyy format, launch and run the SAS program. Review the output to convince yourself that the program does as claimed.
Example 22.15
The following SAS program reads in three dates (date1, date2, and date3) using a ddmmyy informat. Then, the dates are printed using a mmddyy format:
DATA inputdates2;
INPUT @6 date1 ddmmyy6. @13 date2 ddmmyy8. @22 date3 ddmmyy10.;
FORMAT date1 mmddyyd10. date2 mmddyyn8. date3 mmddyyp10.;
DATALINES;
100408 10-04-08 10 04 2008
;
RUN;
PROC PRINT data = inputdates2;
TITLE 'The ddmmyy informat and the mmddyy format';
RUN;
Obs | date1 | date2 | date3 |
---|---|---|---|
1 | 04-10-2008 | 04102008 | 04.10.2008 |
First, review the INPUT statement and the corresponding forms of the April 10, 2008 date in the DATALINES statement. Again, the width of the ddmmyy informat (6, 8, or 10) tells SAS what form of the date it should expect. The "d" that appears in the format for the date1 variable tells SAS to display dashes between the month, day, and year. The "n" that appears in the format for the date2 variable tells SAS to display nothing between the month, day, and year. (Note that the width of the mmddyyn8. format is 8, and not 10. If you specify a width of 10 with the "n" extension, SAS will hiccup.) The "p" that appears in the format for the date3 variable tells SAS to display periods between the month, day, and year.
When you are satisfied you understand the use of the ddmmyy informat and the mmddyy format, launch and run the SAS program. Review the output to convince yourself that the program does as claimed.
Example 22.16
The following SAS program reads in three dates (date1, date2, and date3) using a date informat. Then, the dates are printed using weekdate, worddate, and worddatx formats, respectively:
DATA inputdates3;
INPUT @6 date1 date7. @14 date2 date9. @24 date3 date11.;
FORMAT date1 weekdate25.
date2 worddate19.
date3 worddatx19.;
DATALINES;
10Apr08 10Apr2008 10-Apr-2008
;
RUN;
PROC PRINT data = inputdates3;
TITLE 'The date7 informat and the weekdate and worddate formats';
RUN;
Obs | date1 | date2 | date3 |
---|---|---|---|
1 | Thursday, Apr 10, 2008 | April 10, 2008 | 10 April 2008 |
First, review the INPUT statement and the corresponding forms of the April 10, 2008 date in the DATALINES statement. Note, in particular, that the width of the date informat (7, 9, or 11) tells SAS what form of the date it should expect. Again — SAS will let you know if you incorrectly specify the width of the format!
Then, launch and run the SAS program, and review the output so you can appreciate how dates formatted using the weekdate, worddate and worddatx formats are displayed. If the widths that you specify for these formats are too small, SAS will attempt to abbreviate the date for you. You might want to change the width of the weekdate format to, say, 20 to see this for yourself.
22.4 - SAS Date System Options
22.4 - SAS Date System OptionsThere are two system options that affect how SAS handles dates —the DATESTYLE= and YEARCUTOFF= options.
The DATESTYLE= system option tells SAS your intended sequence of month (M), day (D), and year (Y) when dates are ambiguous. Possible settings include MDY, MYD, YMD, YDM, DMY, DYM, and LOCALE. By default, the DATESTYLE system option is set to LOCALE, which tells SAS to use the form of dates that reflect the language and local conventions of the geographical region specified by the LOCALE system option. Yikes, this sounds circular! Because LOCALE is by default set to ENGLISH for users in the United States, MDY is our default DATESTYLE option. We won't spend any more time on the DATESTYLE system option, but it is something you'll definitely want to know about if you ever get tempted to use the anydtdte. informats to read in dates. (Even though the anydtdte. informats are tempting to use as they allow you to read in different forms of the same date into one date variable, I chose not to present the informat, because I don't like the way it makes SAS have to make decisions about my data!)
SAS developed the YEARCUTOFF= system option to provide users with a way to handle two-digit years. If we specify the date constant '13apr08'd, we could mean 2008, 1908, or even 1808. The YEARCUTOFF = system option eliminates this ambiguity by telling SAS the first year of a 100-year span to be used by date informats and functions when SAS encounters a two-digit year. The default value of YEARCUTOFF is 1920. In the default case, if SAS encounters a two-digit year in your program between 20 and 99, SAS assumes the date has a prefix of 19. And, if SAS encounters a two-digit year in your program between 00 and 19, SAS assumes the date has a prefix of 20. There are two things you can do if you don't like the way SAS is handling your two-digit dates — either use four-digit dates or use the OPTIONS statement to change the default YEARCUTOFF= option. We'll take a look at two examples now just to make sure we understand how SAS handles two-digit years.
Example 22.17
The following SAS program uses the default YEARCUTOFF = 1920 to read in nine dates that contain two-digit years ranging from 20 to 99, and then from 00 to 19:
OPTIONS YEARCUTOFF=1920;
DATA twodigits1920;
INPUT date1 mmddyy8.;
FORMAT date1 worddatx20.;
DATALINES;
01/03/20
01/03/21
01/03/49
01/03/50
01/03/51
01/03/99
01/03/00
01/03/01
01/03/19
;
RUN;
PROC PRINT data=twodigits1920;
title 'Years with two-digits when YEARCUTOFF = 1920';
RUN;
Obs | date1 |
---|---|
1 | 3 January 1920 |
2 | 3 January 1921 |
3 | 3 January 1949 |
4 | 3 January 1950 |
5 | 3 January 1951 |
6 | 3 January 1999 |
7 | 3 January 2000 |
8 | 3 January 2001 |
9 | 3 January 2019 |
First, review the dates in the DATALINES statement to make sure you understand the range of two-digit years that we are trying to read into the twodigits1920 data set. Then, launch and run the SAS program, and review the resulting output. Note that the dates containing two-digit years between 20 and 99 are displayed as four-digit years between 1920 and 1999. And, the dates containing two-digit years between 00 and 19, are displayed as four-digit years between 2000 and 2019.
Example 22.18
The following SAS program is identical to the previous program except the YEARCUTOFF= system option has been changed to 1950. As before, SAS reads in nine dates that contain two-digit years ranging from 20 to 99, and then from 00 to 19:
OPTIONS YEARCUTOFF=1950;
DATA twodigits1950;
INPUT date1 mmddyy8.;
FORMAT date1 worddatx20.;
DATALINES;
01/03/20
01/03/21
01/03/49
01/03/50
01/03/51
01/03/99
01/03/00
01/03/01
01/03/19
;
RUN;
PROC PRINT data=twodigits1950;
title 'Years with two-digits when YEARCUTOFF = 1950';
RUN;
Obs | date1 |
---|---|
1 | 3 January 2020 |
2 | 3 January 2021 |
3 | 3 January 2049 |
4 | 3 January 1950 |
5 | 3 January 1951 |
6 | 3 January 1999 |
7 | 3 January 2000 |
8 | 3 January 2001 |
9 | 3 January 2019 |
Again, review the dates in the DATALINES statement to make sure you understand the range of two-digit years that we are trying to read into the twodigits1950 data set. Then, launch and run the SAS program, and review the resulting output. Note that now the dates containing two-digit years between 50 and 99, are displayed as four-digit years between 1950 and 1999. And, the dates containing two-digit years between 00 and 49, are displayed as four-digit years between 2000 and 2049.
22.5 - SAS Time Basics
22.5 - SAS Time BasicsWe won't spend as much time (no pun intended!) learning how to handle times in SAS as we did learning how to handle dates, but we should still learn the basics. In this section, we'll get a quick and broad overview of the fundamental things you need to know about working with times in SAS. We'll learn how SAS defines time and datetime values, how to use an informat to read a time into a SAS data set, how to use a format to display a SAS time, how to use the most common time functions, and how to define a SAS time constant.
The Definition of a SAS Time and Datetime
SAS stores time values similar to the way it stores date values. Specifically, SAS stores time as a numeric value equal to the number of seconds since midnight. So, for example, SAS stores:
- a 60 for 12:01 am, since it is 60 seconds after midnight
- a 95 for 12:01:35 am, since it is 95 seconds after midnight
- a 120 for 12:02 am, since it is 120 seconds after midnight
- and so on ...
Since there are 86,400 seconds in a day, a SAS time value takes on a value between 0 and 86,400. No matter how you read a time, SAS converts the time to a number as just defined.
A SAS datetime is a special value that combines both date and time values. A SAS datetime value is stored as the number of seconds between midnight on January 1, 1960, and a given date and time. Okay, I don't feel like calculating one of these datetimes out myself. I'll trust the SAS manual that I'm looking at that tells me, for example, that the SAS datetime for April 22, 1989, at 4:10:45 pm equals 92,488,384 seconds. I guess that if you need the added accuracy of working with seconds, then datetimes are for you. I personally have never needed to use them.
Using Informats and Formats to Input and Display a SAS Time
Just as we need to tell SAS what form a date should take, we need to tell SAS what form a time should take. As you'd probably expect, we use time informats in an INPUT statement to tell SAS the form of the times to be read in. And, we use time formats in a FORMAT statement to tell SAS the form of the times to be displayed.
Example 22.19
The following SAS program reads five observations into a SAS data set called diet. One of the variables — weight time (wt_time) — is in hh:mm:ss format, and therefore SAS is told to read the dates using the time8. informat:
DATA diet;
input subj 1-4 l_name $ 18-23 weight 30-32
+1 wt_date mmddyy8. @43 b_date mmddyy8.
@52 wt_time time8.;
wtm_fmt1 = wt_time;
wtm_fmt2 = wt_time;
wtm_fmt3 = wt_time;
format wtm_fmt1 hhmm.
wtm_fmt2 hour5.2
wtm_fmt3 time8.;
DATALINES;
1024 Alice Smith 1 65 125 12/1/05 01/01/60 00:01:00
1167 Maryann White 1 68 140 12/01/05 01/01/59 00:15:00
1168 Thomas Jones 2 190 12/2/05 06/15/60 12:00:00
1201 Benedictine Arnold 2 68 190 11/30/05 12/31/60 00:00:00
1302 Felicia Ho 1 63 115 1/1/06 06/15/58 23:59:59
;
RUN;
PROC PRINT data=diet;
title 'The diet data set with formatted weight times';
var subj wt_time wtm_fmt1 wtm_fmt2 wtm_fmt3;
RUN;
Obs | subj | wt_time | wtm_fmt1 | wtm_fmt2 | wtm_fmt3 |
---|---|---|---|---|---|
1 | 1024 | 60 | 0:01 | 0.02 | 0:01:00 |
2 | 1167 | 900 | 0:15 | 0.25 | 0:15:00 |
3 | 1168 | 43200 | 12:00 | 12.00 | 12:00:00 |
4 | 1201 | 0 | 0:00 | 0.00 | 0:00:00 |
5 | 1302 | 86399 | 24:00 | 24.00 | 23:59:59 |
First, review the program so that you understand what it is doing. Specifically, pay attention to the time8. informat used to read in the wt_time variable. Also, note that three new weight time variables — wtm_fmt1, wtm_fmt2, wtm_fmt3 — are assigned to equal the values of the wt_time variable. The three new variables are each formatted differently, however. The FORMAT statement tells SAS to format wtm_fmt1 as hhmm., wtm_fmt2 as hour5.2, and wtm_fmt3 as time8.
Now, launch and run the SAS program, and review the resulting output to familiarize yourself with the contents of the diet data set. Note, in particular, the numeric values that are stored for the unformatted wt_time variable. As expected, the 00:01:00 time is stored as a 60, the 00:00:00 time is stored as a 0, and the 00:15:00 time is stored as a 900. Then, note the formatted versions of the weight time variables. As you can see, the hhmm. format displays the time on a 24-hour clock. The hour5.2 format displays the time as hours and decimal fractions of hours. And, the time8. format displays the time as hours, minutes, and seconds in the form hh:mm:ss.
Using SAS Time Functions
Just as is the case for SAS dates, the best thing about SAS times is that, because SAS time values are numeric values, you can easily sort them, subtract them, and add them. You can also compare times. Or, you can use them in any of the available time functions. The most commonly used time functions are:
- time( ) returns the current time as a SAS time value
- hms(h, m, s) returns a SAS time value for the given hour (h), minutes (m), and seconds (s)
- hour(time) returns the hour portion of a SAS time value (time)
- minute(time) returns the minute portion of a SAS time value (time)
- second(time) returns the second portion of a SAS time value (time)
We won't look at an example of their use here, but the interval functions intnx( ) and intck( ) that we explored on SAS dates can also be used on SAS times.
Example 22.20
The following SAS program illustrates the use of the five time functions mentioned above. Specifically, the variable curtime is assigned the current time using the time( ) function. Then, the hour( ), minute( ), and second( ) functions are used to extract the hours, minutes, and seconds from the wt_time variable. Finally, the hms( ) function is used to put the hours, minutes, and seconds back together again to create a new variable called wt_time2 that equals the old wt_time variable:
DATA diet;
input subj 1-4 l_name $ 18-23 weight 30-32
+1 wt_date mmddyy8. @43 b_date mmddyy8.
@52 wt_time time8.;
curtime = time();
wt_hr = hour(wt_time);
wt_min = minute(wt_time);
wt_sec = second(wt_time);
wt_time2 = hms(wt_hr, wt_min, wt_sec);
format curtime wt_time wt_time2 time8.;
DATALINES;
1024 Alice Smith 1 65 125 12/1/05 01/01/60 00:01:00
1167 Maryann White 1 68 140 12/01/05 01/01/59 00:15:00
1168 Thomas Jones 2 190 12/2/05 06/15/60 12:00:00
1201 Benedictine Arnold 2 68 190 11/30/05 12/31/60 00:00:00
1302 Felicia Ho 1 63 115 1/1/06 06/15/58 23:59:59
;
RUN;
PROC PRINT data=diet;
title 'The diet data set with five new variables';
var subj curtime wt_time wt_hr wt_min wt_sec wt_time2;
RUN;
Obs | subj | curtime | wt_time | wt_hr | wt_min | wt_sec | wt_time2 |
---|---|---|---|---|---|---|---|
1 | 1024 | 13:09:07 | 0:01:00 | 0 | 1 | 0 | 0:01:00 |
2 | 1167 | 13:09:07 | 0:15:00 | 0 | 15 | 0 | 0:15:00 |
3 | 1168 | 13:09:07 | 12:00:00 | 12 | 0 | 0 | 12:00:00 |
4 | 1201 | 13:09:07 | 0:00:00 | 0 | 0 | 0 | 0:00:00 |
5 | 1302 | 13:09:07 | 23:59:59 | 23 | 59 | 59 | 23:59:59 |
First, review the program to make sure that you understand how to use each of the five functions. Then, launch and run the SAS program, and review the output to convince yourself that the program does as claimed.
Comparing Times
Again, because SAS time values are numeric values, you can easily compare two or more times The comparisons are made just as the comparisons between any two numbers would take place. For example, because the time 00:10:00 is stored as a 600 in SAS, it is considered smaller than the time 00:15:00, which is stored as a 900 in SAS.
Example 22.21
The following SAS program illustrates how to compare the values of a time variable, not to the values of some other time variable, but rather to a time constant. Specifically, the WHERE= option on the DATA statement tells SAS to output to the diet data set only those individuals whose wt_time is between midnight and noon, inclusive:
DATA diet (where = ((wt_time ge '00:00:00't)
and (wt_time le '12:00:00't)));;
input subj 1-4 l_name $ 18-23 weight 30-32
+1 wt_date mmddyy8. @43 b_date mmddyy8.
@52 wt_time time8.;
time_int = abs((wt_time - '05:00:00't)/3600);
format wt_time time8. time_int 4.1;
DATALINES;
1024 Alice Smith 1 65 125 12/1/05 01/01/60 00:01:00
1167 Maryann White 1 68 140 12/01/05 01/01/59 00:15:00
1168 Thomas Jones 2 190 12/2/05 06/15/60 12:00:00
1201 Benedictine Arnold 2 68 190 11/30/05 12/31/60 00:00:00
1302 Felicia Ho 1 63 115 1/1/06 06/15/58 23:59:59
;
RUN;
PROC PRINT data=diet;
title 'The subsetted diet data set';
var subj l_name wt_time time_int;
RUN;
Obs | subj | l_name | wt_time | time_int |
---|---|---|---|---|
1 | 1024 | Smith | 0:01:00 | 5.0 |
2 | 1167 | White | 0:15:00 | 4.8 |
3 | 1168 | Jones | 12:00:00 | 7.0 |
4 | 1201 | Arnold | 0:00:00 | 5.0 |
First, review the program to make sure you understand what it is doing. Note, for example, the form of the SAS time constants:
'00:00:00't
and
'12:00:00't
used in the WHERE= option. In general, a SAS time constant takes the form 'hh:mm:ss't where hh is the hour in 24-hour time, mm is the minutes, and ss (optional) are the seconds. The letter t that follows the time in single quotes tells SAS to treat the time string like a constant. Note that regardless of how you have informatted or formatted your SAS times, the SAS time constant always takes the above form.
This program also illustrates how you can use SAS time variables easily in calculations. The variable time_int is assigned the absolute difference in time, in hours, between each individual's weight time and their expected weight time, say for example, 5 a.m.
Now, launch and run the SAS program. Then, review the resulting output to convince yourself that only those individuals whose weight time is between midnight and noon are included in the output diet data set.
Well, I think that's enough for now about processing time values in SAS. As you can see, times are treated just as dates are in SAS. Once you understand one, you understand the other. Now, let's practice what we've learned in this lesson!
22.6 - Summary
22.6 - SummaryIn this lesson, we've learned various aspects of processing dates and times within the SAS System.
The homework for this lesson will give you more practice with these techniques so that you become even more familiar with how they work and can use them in your own SAS programming.