Yes, it's.
Reeza wrote:
Oh, yeah proc fcmp isn't until 9.2 at least.
Convert to SAS date based on the following then, assuming you do the conversion to day, month, year as indicated:
You can still take the difference of the dates to get duration.
data test;
year=1435;
day=28;
month=12;
sas_date=((day+ceil(29.5*(month-1))+(year-1)*354+
floor((3+(11*year))/30)+1948439.5)-1)-2436934.5;
format sas_date date9.;
run;
PROC FCMP definitely does exist in 9.1.3, however, the user-defined functions themselves were not accessible in the data step until 9.2. In 9.1.3 they are only available in a few select PROCS.
: Matt won't be able to check our macro's code until sometime next week, but the following should come close:
%macro islamic_to_jd(year,month,day);
(&day.+ceil(29.5*(&month-1))+(&year.-1)*354+
floor((3+(11*&year.))/30)+1948439.5)-1-2436935.5
%mend islamic_to_jd;
data have;
informat islamic_date1 islamic_date2 $10.;
input islamic_date1 islamic_date2;
format sd1 sd2 date9.;
sd1=%islamic_to_jd(scan(islamic_date1,1,'-'),scan(islamic_date1,2,'-'),
scan(islamic_date1,3,'-'));
sd2=%islamic_to_jd(scan(islamic_date2,1,'-'),scan(islamic_date2,2,'-'),
scan(islamic_date2,3,'-'));
days_between=sd2-sd1;
cards;
1393-02-31 1393-07-30
1393-02-31 1435-12-28
1435-12-29 1436-01-17
;
Hardly thanks. But this code was wrong.
For Iranian date duration between 1393-02-31 and 1393-07-30 is 154 days not 146 days.
Best regards
Hi Everyone,
I have just returned from a vacation, so excuse the cobwebs as I readjust back into things.
I am trying to do the same and found a custom function ISLAMIC_TO_SD here:
http://www.sascommunity.org/wiki/Sometimes_One_Needs_an_Option_with_Unusual_Dates
(Click here to download the SAS code for creating Hebrew and Islamic calendar interval datasets)However, I tested it with today's date (2014-10-23) and the Islamic date is off by one day (1435-12-28 instead of 1435-12-29).
I wonder if the author of that function could help...
There are two values for epoch that can be used in this calculation, one I used in the paper referenced in this thread and the other, which my research previously showed to be used less frequently, that you desire. Here is a new FCMP routine for converting SAS dates for a WEEKDATX. type format:
proc fcmp outlib=work.func.kuwaiti;
subroutine _kuwaiti(sasdate, imDate[3]);
outargs imDate;
d=day(sasdate);
m=month(sasdate);
y=year(sasdate);
if (m<3) then do;
y+-1;
m++12;
end;
a=floor(y/100);
b=2-a+floor(a/4);
if (y<1583) then b=0;
else if (y=1582) then do;
if (m>10) then b=-10;
else if (m=10) then do;
b=0;
if (d>4) then b=-10;
end;
end;
jd=floor(365.25*(y+4716))+floor(30.6001*(m+1))+d+b-1524;
b=0;
if jd>2299160 then do;
a=floor((jd-1867216.25)/36524.25);
b=1+a-floor(a/4);
end;
bb=jd+b+1524;
cc=floor((bb-122.1)/365.25);
dd=floor(365.25*cc);
ee=floor((bb-dd)/30.6001);
day=(bb-dd)-floor(30.6001*ee);
month=ee-1;
if(ee>13) then do;
cc+1;
month=ee-13;
end;
year=cc-4716;
wd=mod((mod(jd+1,7)+7),7);
iyear = 10631/30;
epochastro = 1948084;
epochcivil = 1948085; /*alternate epoch*/
shift1 = 8.01/60;
z = jd-epochastro;
cyc=floor(z/10631);
z=z-10631*cyc;
j=floor((z-shift1)/iyear);
iy=30*cyc+j;
z=z-floor(j*iyear+shift1);
im=floor((z+28.5001)/29.5);
if im=13 then im=12;
id=z-floor(29.5001*im-29);
imDate[1]=iy; /*islamic year*/
imDate[2]=im; /*islamic month*/
imDate[3]=id; /*islamic day of month*/
endsub;
function kuwaitidate(sasdate) $ 200;
array iDate[3] / nosymbols;
array iMon[12] $ 14 _temporary_ ("Muharram","Safar","Rabi'ul Awwal","Rabi'ul Akhir",
"Jumadal Ula","Jumadal Akhira","Rajab","Sha'ban",
"Ramadan","Shawwal","Dhul Qa'ada","Dhul Hijja");
call _kuwaiti(sasdate, iDate);
return (put(sasdate,downame.) || ', ' || strip(put(iDate[3],best.)) || ' ' || strip(iMon[iDate[2]]) || ' ' || strip(put(iDate[1],best.)) || ' AH');
endsub;
/*example usage*/
length x $2000;
x=kuwaitidate('27OCT2014'd);
put x=;
quit;
x=Monday, 4 Muharram 1436 AH
You could then create a format with this function as so,
options cmplib=(work.func);
proc format;
value kuwaitidate other=[kuwaitidate()];
run;
%put %sysfunc(today(), kuwaitidate.);
zanam When I read that Islamic calendar - Wikipedia, the free encyclopedia the Islamic calendar may differ from country to country and may be by who is whatching the moon theres is not one but many of those.
In that case it is more a standard that everybody has his one for (other words, no standards). A conversion only makes sense when there is a exact definition at both sides. What is your calendar definition?
Thanks for your post.
Yes, unfortunately it is different between Islamic countries. For Iran, it determined as Persian date (Iranian calendars - Wikipedia, the free encyclopedia).
Zana
What I was thinking on was:
- the Tabular Islamic calendar - Wikipedia, the free encyclopedia. being more mathematical. But it is discrepedancy within all those different streams
- The day is just a numerical sequence. Every day another, next, number. Wether calculated in formulas (rounding/precion) using eg a FCMP routine with formats (in/out) should be able to cover that.
The intervalds dataset to be used for dedicated intervals. It is just translating that number to some text vice versa for formats. The week interval should be able to be used but others needing a different approach..
I missed the 9.1.3 limitation. You could upgrade to a newer version. As long you are at that one fcmp is not possible.
The most basic approach for formats / informats will be defining a long list of values to the associated SAS day-number vice versa, it could be generated for a defined period. inputting yyyy-mm-dd islamtic for let us say 200 years is 73000 records.
is that limited period a problem?
Trying to convert it to formats, see date_persionhirji.sas attached file.
To creating of the control file is not as I like as is the format behavior. With 10 chars it is looking to be coming alive.i
This is result on testing
43 /* test Iranian_Date Gregorian_Date */
44 data val_fmts;
45 infile datalines dsd;
46 input hiridat hiri_dat10. +2 dategrg date10. ;
47 Put _all_ ;
48 put hiridat hiri_dat12. " " hiridat date10. " --- " dategrg date10. " " dategrg hiri_dat. ;
49 cards;
hiridat=19724 dategrg=19724 _ERROR_=0 _N_=1
1392-10-11 01JAN2014 --- 01JAN2014 1392-10-11
hiridat=19803 dategrg=19803 _ERROR_=0 _N_=2
1393-01-01 21MAR2014 --- 21MAR2014 1393-01-01
hiridat=19854 dategrg=19864 _ERROR_=0 _N_=3
1393-02-21 11MAY2014 --- 21MAY2014 1393-02-31
hiridat=19987 dategrg=19987 _ERROR_=0 _N_=4
1393-06-30 21SEP2014 --- 21SEP2014 1393-06-30
hiridat=20020 dategrg=20020 _ERROR_=0 _N_=5
1393-08-02 24OCT2014 --- 24OCT2014 1393-08-02
NOTE: The data set WORK.VAL_FMTS has 5 observations and 2 variables.
NOTE: DATA statement used (Total process time):
real time 0.02 seconds
cpu time 0.04 seconds
Hardly thanks for your kinds. When i run your code the last code have an error as:
953 data val_fmts;
954 infile datalines dsd;
955 input hiridat hiri_dat10. +2 dategrg date10. ;
956 Put _all_ ;
957 put hiridat hiri_dat12. " " hiridat date10. " --- " dategrg date10. " " dategrg hiri_dat.;
------- -------
29 29
ERROR 29-185: Width specified for format DATE is invalid.
Try it with date9. However, while I have to check it again, Jaap's format appears to misapply 1393-02-21
Give me a minute to test my own code (that I hadn't posted since Jaap's code looked correct).
Zana the length difference date foratas are allowing 10. 9. is a one of the changes 9.1.3 you are running to 9.4 I used. SAS 9.1.3 Documentation is only found back in pdf format. I missed that.
Thank you so much. Your code was helpful.
But when i run your code, as you wrote in the last post, i can't found any these results in the output file (Val_fmts). These results are in log window only.
1006 data val_fmts;
1007 infile datalines dsd;
1008 input hiridat hiri_dat10. +2 dategrg date10. ;
1009 Put _all_ ;
1010 put hiridat hiri_dat12. " " hiridat date9. " --- " dategrg date9. " " dategrg hiri_dat. ;
1011 cards;
hiridat=19724 dategrg=19724 _ERROR_=0 _N_=1
1392-10-11 01JAN2014 --- 01JAN2014 1392-10-11
hiridat=19803 dategrg=19803 _ERROR_=0 _N_=2
1393-01-01 21MAR2014 --- 21MAR2014 1393-01-01
hiridat=19854 dategrg=19864 _ERROR_=0 _N_=3
1393-02-21 11MAY2014 --- 21MAY2014 1393-02-31
hiridat=19987 dategrg=19987 _ERROR_=0 _N_=4
1393-06-30 21SEP2014 --- 21SEP2014 1393-06-30
hiridat=20021 dategrg=20020 _ERROR_=0 _N_=5
1393-08-02 24OCT2014 --- 24OCT2014 1393-08-02
NOTE: The data set WORK.VAL_FMTS has 5 observations and 2 variables.
NOTE: DATA statement used (Total process time):
real time 0.03 seconds
cpu time 0.03 seconds
The following seems to work correctly (assuming the page on wikipedia [Iranian calendars - Wikipedia, the free encyclopedia] has the correct date ranges):
data ctrl (keep=fmtname type start label);
informat gdates $31.;
infile cards dlm='09'x;
input _pyear $ gdates &;
retain fmtname 'pdate' type 'j';
leap=index(_pyear,'*');
pyear=input(compress(_pyear,'*'),12.);
bday=input(scan(gdates,1,'.'),12.);
byear=input(scan(gdates,3),12.);
bmonth=3;
if _n_ eq 1 then label=mdy(bmonth,bday,byear)-1;
do pmonth=1 to 12;
if pmonth le 6 then eday=31;
else if pmonth le 11 then eday=30;
else if leap then eday=30;
else eday=29;
do pday=1 to eday;
label+1;
start=catx('-',pyear,put(pmonth,z2.),put(pday,z2.));
output;
end;
end;
cards;
1354* 21. March 1975 – 20. March 1976
1355 21. March 1976 – 20. March 1977
1356 21. March 1977 – 20. March 1978
1357 21. March 1978 – 20. March 1979
1358* 21. March 1979 – 20. March 1980
1359 21. March 1980 – 20. March 1981
1360 21. March 1981 – 20. March 1982
1361 21. March 1982 – 20. March 1983
1362* 21. March 1983 – 20. March 1984
1363 21. March 1984 – 20. March 1985
1364 21. March 1985 – 20. March 1986
1365 21. March 1986 – 20. March 1987
1366* 21. March 1987 – 20. March 1988
1367 21. March 1988 – 20. March 1989
1368 21. March 1989 – 20. March 1990
1369 21. March 1990 – 20. March 1991
1370* 21. March 1991 – 20. March 1992
1371 21. March 1992 – 20. March 1993
1372 21. March 1993 – 20. March 1994
1373 21. March 1994 – 20. March 1995
1374 21. March 1995 – 19. March 1996
1375* 20. March 1996 – 20. March 1997
1376 21. March 1997 – 20. March 1998
1377 21. March 1998 – 20. March 1999
1378 21. March 1999 – 19. March 2000
1379* 20. March 2000 – 20. March 2001
1380 21. March 2001 – 20. March 2002
1381 21. March 2002 – 20. March 2003
1382 21. March 2003 – 19. March 2004
1383* 20. March 2004 – 20. March 2005
1384 21. March 2005 – 20. March 2006
1385 21. March 2006 – 20. March 2007
1386 21. March 2007 – 19. March 2008
1387* 20. March 2008 – 20. March 2009
1388 21. March 2009 – 20. March 2010
1389 21. March 2010 – 20. March 2011
1390 21. March 2011 – 19. March 2012
1391* 20. March 2012 – 20. March 2013
1392 21. March 2013 – 20. March 2014
1393 21. March 2014 – 20. March 2015
1394 21. March 2015 – 19. March 2016
1395* 20. March 2016 – 20. March 2017
1396 21. March 2017 – 20. March 2018
1397 21. March 2018 – 20. March 2019
1398 21. March 2019 – 19. March 2020
1399* 20. March 2020 – 20. March 2021
1400 21. March 2021 – 20. March 2022
1401 21. March 2022 – 20. March 2023
1402 21. March 2023 – 19. March 2024
1403* 20. March 2024 – 20. March 2025
1404 21. March 2025 – 20. March 2026
1405 21. March 2026 – 20. March 2027
1406 21. March 2027 – 19. March 2028
1407 20. March 2028 – 19. March 2029
1408* 20. March 2029 – 20. March 2030
1409 21. March 2030 – 20. March 2031
1410 21. March 2031 – 19. March 2032
1411 20. March 2032 – 19. March 2033
1412* 20. March 2033 – 20. March 2034
1413 21. March 2034 – 20. March 2035
1414 21. March 2035 – 19. March 2036
1415 20. March 2036 – 19. March 2037
1416* 20. March 2037 – 20. March 2038
1417 21. March 2038 – 20. March 2039
1418 21. March 2039 – 19. March 2040
1419 20. March 2040 – 19. March 2041
;
proc format library=work cntlin=ctrl;
run;
data want;
informat persian_date1 persian_date2 $10.;
input persian_date1 persian_date2;
format sd1 sd2 date9.;
sd1=input(persian_date1,$pdate10.);
sd2=input(persian_date2,$pdate10.);
days_between=sd2-sd1;
cards;
1392-10-11 1393-01-01
1393-02-31 1393-06-30
1393-08-02 1395-03-02
;
Thanks for your post.
Unfortunately $pdate was unknown for mine.
1313 data want;
1314 informat persian_date1 persian_date2 $10.;
1315 input persian_date1 persian_date2;
1316 format sd1 sd2 date9.;
1317 sd1=input(persian_date1,$date10.);
--------
48
ERROR 48-59: The informat $DATE was not found or could not be loaded.
1318 sd2=input(persian_date2,$pdate10.);
---------
48
ERROR 48-59: The informat $PDATE was not found or could not be loaded.
1319 days_between=sd2-sd1;
1320 cards;
Available on demand!
Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.