BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
FriedEgg
SAS Employee

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.

art297
Opal | Level 21

: 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

;

zana
Calcite | Level 5

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

FriedEgg
SAS Employee

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.);

jakarman
Barite | Level 11

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?  

---->-- ja karman --<-----
zana
Calcite | Level 5

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

jakarman
Barite | Level 11

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?   

---->-- ja karman --<-----
jakarman
Barite | Level 11

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

---->-- ja karman --<-----
zana
Calcite | Level 5

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.

art297
Opal | Level 21

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).

jakarman
Barite | Level 11

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.

---->-- ja karman --<-----
zana
Calcite | Level 5

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.Smiley Sad

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

art297
Opal | Level 21

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

;

zana
Calcite | Level 5

Thanks for your post.

Unfortunately $pdate was unknown for mine.Smiley Sad

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;

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 42 replies
  • 5161 views
  • 6 likes
  • 9 in conversation