SAS format : full month name to integer - formatting

what is the best to format full month name to integer in SAS?
'January' --> 1
'February' --> 2

You could do this without a format:
data test;
monthtext="January";
month=month(input("01"||substr(monthtext,1,3)||"2000",date9.));
run;

You can make your own format:
options fmtsearch=(work);
proc format;
invalue MonNum
JANUARY = 1
FEBRUARY = 2
;
run;
data Month;
length month $10;
input Month $;
month=upcase(month);
monthnum=input(month,monnum.);
datalines;
January
February
;
Run;
Proc report data=work.month nowd;
column month monthnum;
run;

An approach using input function to convert character type to numerical type. But I will agree that creating custom format is better then.
data test;
input monthchar $15.;
datalines;
December
January
March
;
run;
data test;
set test;
monthnum=month(input(cats(1,substr(monthchar,1,3),2000),date9.));
run;

It depends on how you are going to use this in your code. If you need to repeat this mapping in multiple sections of your code then I would suggest creating a custom format using PROC FORMAT which can be used in data steps or in other procedures. If you are just doing this mapping in one data step, then you could use SELECT/WHEN or IF/ELSE IF logic to do the same. There are many other ways to accomplish this in SAS, but I think these two methods are the most straight forward.

Related

How to extract records in SAS PROC SQL passthru, filtered by date, but the date is in string format?

I'm trying to extract data from date range (set by start_date and end_date variables defined in the null step).
Usually I would do this using passthru PROC SQL, as follows:
PROC SQL;
CONNECT TO ORACLE AS xxxxx (AUTHDOMAIN="xxxxx" PATH=xxxxx preserve_comments);
CREATE TABLE
work.new_data AS
SELECT
*
FROM
CONNECTION TO xxxxx (SELECT /*+parallel(16)*/ var1, var2, var3
FROM
oracle_data
WHERE date >= &start_date. AND date <= &end_date.);
DISCONNECT FROM xxxxx;
QUIT;
This extracts the data much more efficiently than doing it through a data step or pulling all the data and then filtering it.
The problem is with this particular dataset I'm using, the datetime is stored as a string in the format "DD/MM/YYYY HH:MM:SS". I know how to convert this normally in a data step or such, but the problem is I cannot convert it or interpret it as a date in the PROC SQL passthru stage.
Replacing the WHERE step with any SAS function like below throws an "Oracle Prepare Error" as it doesn't recognize the functions. I've also tried using SQL functions for something similar in the past and they also didn't work and I didn't manage to find a solution.
WHERE DATEPART(INPUT(rtp_date,anydtdtm.)) >= &start_date.)
Is it possible to interpret a string as datetime in the passthru stage and use it for filtering? Or is there perhaps another way to do this which is still more efficient than pulling everything or performing a data step directly onto the oracle data?
When you pass through date criteria to Oracle, one construct for the server side date literal is literally
DATE 'yyyy-mm-dd'
For the task of populating macro variables with source code that is Oracle source code for a date literal you will need to interpret your SAS datetime string, retrieve the date part and render that value as an Oracle date literal.
Example:
options nosource;
data have;
length task start_date_string end_date_string $19;
input task start_date_string& end_date_string&;
datalines;
task1 31/01/2020 08:09:10 02/02/2020 11:00:00
task2 15/03/2019 02:00:00 19/03/2019 23:00:00
;
proc sql noprint;
select start_date_string, end_date_string into :start_date, :end_date
from have where task='task1';
%put &=start_date;
%put &=end_date;
%let s_datepart_val = %sysfunc(inputn(&start_date,ddmmyy10.));
%let e_datepart_val = %sysfunc(inputn(&end_date,ddmmyy10.));
%put &=s_datepart_val;
%put &=e_datepart_val;
%let ora_start_literal = DATE %str(%')%sysfunc(putn(&s_datepart_val,yymmdd10.))%str(%');
%let ora_end_literal = DATE %str(%')%sysfunc(putn(&e_datepart_val,yymmdd10.))%str(%');
%put &=ora_start_literal;
%put &=ora_end_literal;
---------- LOG ----------
START_DATE=31/01/2020 08:09:10
END_DATE=02/02/2020 11:00:00
S_DATEPART_VAL=21945
E_DATEPART_VAL=21947
ORA_START_LITERAL=DATE '2020-01-31'
ORA_END_LITERAL=DATE '2020-02-02'
And an alternate approach to populating the macro variables containing the date literals;
proc sql noprint;
select
'DATE ' || quote(put(input(start_date_string,ddmmyy10.),yymmdd10.),"'")
, 'DATE ' || quote(put(input( end_date_string,ddmmyy10.),yymmdd10.),"'")
into
:ora_start_literal
, :ora_end_literal
from
have
where
task = 'task2'
;
%put &=ora_start_literal;
%put &=ora_end_literal;
---------- LOG ----------
ORA_START_LITERAL=DATE '2019-03-15'
ORA_END_LITERAL=DATE '2019-03-19'
The pass through would utilize the 'literal' macro variables
WHERE date >= &ora_start_literal. AND date <= &ora_end_literal;
We use formats to simplify the process.
Create a format called oracledt. that takes a datetime value and converts it to the format 'mm/dd/yy hh:mm:ss' (including the quotes).
proc format lib=work;
picture oracledt low-high = '''%0m/%0d/%y %0H:%0M:%0S''' (datatype = datetime) ;
run ;
Create a macro variable called my_datetime that contains the current datetime formatted with the above custom format:
%let my_datetime = %sysfunc(datetime(), oracledt.);
%put &=my_datetime;
Output:
MY_DATETIME='02/28/20 09:13:17'
This whitepaper describes the various values you can use when building your own custom format: http://www2.sas.com/proceedings/forum2007/026-2007.pdf
If the format you're after is 'yyyy-mm-dd hh:mm:ss' then your format definition would look like this: '''%Y-%0m-%0d %0H:%0M:%0S'''.
As Richard demonstrates, it is a good practice to keep your dates/datetimes stored as SAS dates/datetime values so that you can work with them, and then create additional variables to be used for the passthrough statement.

DD MON YYYY to YYMMn6

I am writing a program in Proc SQL. the program takes various input files, where the filenames change from month to month (i.e. myfile_YYYY_MM or mytable_YYYYMM, or mydata_YY_M).
Most of the program is now dynamic, and the user is asked to input reporting date via a prompt when executing the program.
The "Prompt Date" (&Rep_Date.) in the code has format DD MON YYYY (31may2018), and I need to set up one macro variable transforming this value to format YYMMn6 (i.e. 201805).
The syntax looks like this:
%let Period = input("&Rep_Date."d,YYMMN.);
This worked when trying to create a d9 variable, and for creating a month/year variable, like this:
%let date = "&Rep_Date."d; /*Last day execution month*/
%let year = %sysfunc(year("&Rep_Date."d));
%let month = %sysfunc(month("&rep_Date."d));
for some reason, the same does not work when trying to format the date to YYMMn6.
I also tried creating the variable "Period" in a temporary SAS table like this, but again no luck:
Data dates;
Period = input((&Rep_date.,6.), yymmn6.);
format Period yymmn6.;
Run;
Any ideas on where I am going wrong?
I believe the problem is because of the fact that you are using just the input function in your %let statement.. This won't resolve properly. The right thing would be to use the %sysfunc macro function with the input function. The issue is that sysfunc doesn't work with the input function. Hence, the solution is to use %sysfunc(putn()). Here is an example.
Edit:
Not sure what you're trying to achieve but the %window function (assuming you're using Windows) allows you to take input through a prompt and then create a macro variable from the input. Here is an example:
%global Period;
%window info
#5 #5 'Please enter date:'
#5 #40 _Date 9 attr=underline;
%display info;
%put &_Date.;
%macro da(Rep_Date=&_Date);
%let Period = %sysfunc(putn("&Rep_Date."d,YYMMN.));
%put &Period.;
%mend;
%da();
This should work.
What is going wrong ? You are mixing contexts and misconstruing a representation as a literal (literally - pun literally intended).
In short
Have your macro code utilize the date representation value as the basis for a literal value that is used in a putN() invoked by %sysfunc.
%let Rep_Date = 18-JUN-2018; * some date representation;
%let Period = %sysfunc(PUTN("&Rep_Date."D,YYMMN.));
%put NOTE: Period=%superq(Period);
In Long
From the Glossary in "SAS Help and Documentation" (F1)
SAS date valuean integer that represents a date in SAS software. The integer represents the number of days between January 1, 1960, and another specified date. For example, the SAS date value 366 represents the calendar date January 1, 1961.
SAS date constanta string in the form 'ddMMMyy'd or 'ddMMMyyyy'd that represents a date in a SAS statement. The string is enclosed in quotation marks and is followed by the character d (for example, '6JUL01'd, '06JUL01'd, '6 JUL2001'd, or '06JUL2001'd).
date and time formatinstructions that tell SAS how to write numeric values as dates, times, and datetimes.
date and time informatthe instructions that tell SAS how to read numeric values that are represented as dates, times, and datetimes.
Textual values of the form DD MON YYYY is one form of a representation of a date. The form with four year digits can be input using the instructions inherent in the informat DATE11.. The SAS date literals (SAS date constant) are of the form DDMONYYYYD with or without a variety of spaces, dashes, slashes, etc.
Another code variation similar to the 'In short' would input the date text using a specific format (date11.) instead of relying on the system doing a date literal interpretation.
%let Rep_Date_text_representation = 18/JUN/2018;
%let Rep_Date_value = %sysfunc(inputN(&Rep_Date_text_representation,date11.));
%let Period = %sysfunc(putn(&Rep_Date_Value,yymmn.));
%put NOTE: &=Rep_Date_text_representation ;
%put NOTE: &=Rep_Date_value;
%put NOTE: &=Period;

Convert Month_Dt In sas

I have a sample data in this format as char.
Month
2008-09
2007-10
2008-09
How to get the above as date '01sep2008' (SAS DESIGN STUDIO)
There are a few ways to do this. Dirk has a good method concatenating a day onto the string and using the INPUT() function.
You could also use the yymmn6. informat with the INPUT(). That requires you to strip the '-' from the string.
data test;
x = '2008-05';
format y date9.;
y = input(compress(x,"-"),yymmn6.);
put y;
run;
You could use the MDY() to specify the Month, Day and Year. Here you use the SCAN() function to pick out the month and year from the string using '-' as a delimiter.
data test;
x = '2008-05';
format y date9.;
y = mdy(scan(x,2,'-'),1,scan(x,1,'-'));
put y;
run;
Use an input function
An input function is a function that interpretes a character variable using an informat. _(This is not exactly the same as an input statement, which interpretes text in an infile according to an informat.)
There might be an informat that imidiately interpretes strings like 2008-09 correctly, but I don't know one, so I just add a _01 to it and apply the informat yymmdd10.
Example
Depending on your situation (the data is inform a file or a dataset / you prefer data steps or sql / ...) the full solution would look like this:
data Before;
input the_date $7.;
datalines;
2008-09
2007-10
2008-09
;
data After;
set Before (rename=(the_date=old_date));
format the_date date9.;
the_date = input(old_date||'-01', yymmdd10.);
* while testing the code, uncomment the following line :
drop old_date;
proc print;
run;

SAS SQL Datepart function returning odd values

I'm having a massive problem with a project that I just can't seem to get right. I'm trying to modify my data variable as its currently in a datetime format. The first data is 30Mar12:00:00:00. I've been advised to use the code below but it returns a value like 30mar60:5:30:00. I just want the date component and have no idea how the data even got exported in this format as it wasn't like this in Microsoft Access. I've tried several mods to this code but again just comes up completely blank or sends an error message.
proc sql; update dataset set date = DATEPART(date); quit;
Any advice would be greatly appreciated.
I'm guessing the variable date is numeric and formatted as DATETIME. Once you've carried out the conversion, just change the format to something like DATE9. A SAS datetime value is the number of seconds since 01 Jan 1960, whereas dates are the number of days since 01 Jan 1960. Both are stored as numbers, so using the correct format to display the value is key. Example below.
data _null_;
a='30Mar12:00:00:00'dt;
b=datepart(a);
c=b;
format a b datetime. c date9.;
put a b c;
run;

Quarter as a Count variable in SAS

Hye Guys,
I'm busy working on a time series and am trying to find the commands that allow me to insert a quarter count variable. To keep things simple, the third quarter of 1995 (date my observations start) should be quarter -2, the fourth quarter of 1995 should be -1 etc etc uptill 2006 (should be somewhere around 45 by then). My dates are in date9 format, such as 20JUN04 etc..
Anyone who can help me with the commands I need t o let this work in SAS?
Thanks
SAS has pretty good built in date and datetime functions. Try this:
/* Some sample data */
data dates;
format dateval date9.;
informat dateval date9.;
input dateval;
datalines;
'01JUL95'
'01OCT95'
'01JAN96'
'20JUN04'
;
run;
/* Sample of the intck function */
data _null_;
set dates;
quarter=intck('qtr','01JAN96'd,dateval);
put _all_;
run;