سؤال

وأحتاج لحساب وهو رقم يعادل عدد "أقرب" الأشهر بين تاريخين. ولكن وظيفة SAS القياسية (INTCK) لا توجه للنظر في DAY المعلمات تاريخه (مثل كود يحل أدناه ل0 عندما كنت في حاجة إليها تقريبه إلى 1).

ما هو 'أبرع' طريقة لحل هذه القضية؟

data _null_;
    x="01APR08"d;
    y="28APR08"d;
    z=intck('MONTH',x,y);
    put z= ;
run;

وتحرير: ردا على تعليق مارتينز

وأود أن جولة 0 أشهر - أنا لا أعتقد أن الحدود غير ذات الصلة. وظيفة واني اسعى لتكرار (NEAREST_MONTHS) تأتي من DCS (سن غارد تطبيق نبي). أنا الآن في انتظار فرصة لإجراء بعض التجارب داخل التطبيق نفسه لفهم المزيد عن الطريقة التي يعامل التواريخ (سيتم نشر النتائج مرة أخرى هنا)).

وملف المساعدة يحتوي على ما يلي: الفئة تاريخ

والوصف

وإرجاع الفرق بين تاريخين إلى أقرب عدد من الشهور. إذا كان التاريخ الثاني هو في وقت لاحق من التاريخ الأول ثم 0 تم إرجاعها.

وبناء الجملة

وNEAREST_MONTHS (Later_Date، Earlier_Date)

عودة نوع صحيح

أمثلة

وNEAREST_MONTHS (DATE1، DATE2) يعود 8 إذا DATE1 هو 20/3/1997 وDATE2 هو 23/7/1996

وNEAREST_MONTHS (DATE1، DATE2) يعود 26 إذا DATE1 هو 20/3/1997 وDATE2 هو 1995/01/02

هل كانت مفيدة؟

المحلول

وكتبت في ذلك وظيفة وأعتقد أن تحسب بنفس الطريقة مثل التطبيق DCS. ويستخدم بعض الميزات التي هي جديدة لSAS في الإصدار 9.2 بما في ذلك التحالفات مستمرة في التواريخ. كما أنها تعمل إلى الأمام أو الوراء في الوقت المناسب (أي يعطي عدد صحيح سالب إذا earlier_date هو بعد later_date). كنت أكثر من 15 يوما وراء الفاصلة مثل قطع تقريبه إلى الشهر المقبل ولكن يمكنك قرص هذا إذا كنت تفضل ذلك.

proc fcmp outlib=work.myfuncs.dates;
   function nearest_months(later_date,earlier_date);
        /* Return missing if inputs are missing */
        if (earlier_date eq . ) OR (later_date eq . ) then
            nearest_month=.;
        else do; 
            /* Use 'cont' argument for continuous dates */
            months=intck('MONTH',earlier_date,later_date,'cont');
            if months < 0 then months=months+1;
            days= later_date - intnx('month', earlier_date,months,'same');

            /* Handle negatives (earlier dates) */
            if months < 0 then do;
                if days < -15 then months=months-1;
                nearest_month=months;
                end;
            else do;
                if days > 15 then months + 1;
                nearest_month=months;
                end;
        end;
        return(nearest_month);
   endsub;
run;
options cmplib=work.myfuncs;


data _null_;
x=nearest_months('20Mar1997'd, '23JUL1996'd);
put x=;
x=nearest_months('20Mar1997'd, '01FEB1995'd);
put x=;
run;

وهذا يعطي نفس رجوع اليها:

x=8
x=26

نصائح أخرى

هل يمكن استخدام INTNX لمعرفة ما إذا كان لجولة صعودا أو هبوطا، منها مثلا.


data _null_;
  format x y date9. z 8.;
  x="01APR08"d;
  y="28APR08"d;
  z=intck('MONTH',x,y);

  * wl is x + z months;
  wl=intnx('MONTH',x,z);

  * wu is x + (z+1) months;
  wu=intnx('MONTH',x,z+1);

  * If y is closer to wu, then adjust z by 1;
  if (abs(y-wu) lt abs(y-wl)) then z = z+1;     

  put x y z=;
run;

إذا قمت بتعريف شهر لتكون 30 يوما، هل الجولة 15 يوما أو أقل وصولا الى 0 أشهر، و 16 يوما أو أكثر تصل إلى 1 في الشهر. ويمكن تحقيق ذلك عن طريق ما يلي:

data _null_;
  format x y date9. z 8.;
  x="14FEB09"d;
  y="02MAR09"d;

  z=round(intck('DAY',x,y)/31);
  put x y z=;
run;

ويمكنك أيضا أن تأخذ النهج لحساب أشهر كاملة ( "1 الأول إلى 1 الماضي") في هذه الفترة، ثم تضيف ما يصل أي الأيام المتبقية لمعرفة إذا كانت نلخص إلى 0 أو 1 أو 2 أشهر. مثل هذا:

data _null_;
  format x y date9. z 8.;
  x="01FEB09"d;
  y="31MAR09"d;

  if day(x)=1 then do;
     z=intck('MONTH',x,intnx('MONTH',y,0,'BEGINNING'))
         + round((intck('DAY',intnx('MONTH',y,0,'BEGINNING'),y))/31);
  end;
  else do;
     z=intck('MONTH',intnx('MONTH',x,1,'BEGINNING'),intnx('MONTH',y,0,'BEGINNING'))
         + round((intck('DAY',x,intnx('MONTH',x,1,'BEGINNING'))+intck('DAY',intnx('MONTH',y,0,'BEGINNING'),y))/31);
  end;
  put x y z=;
run;

والطريقة الأولى هي أسهل للفهم والمحافظة، ولكن الثاني هو أكثر دقة لفترات كبيرة (01FEB06 إلى 01FEB09 هو 36 شهرا، ولكن الأسلوب 1 اقول لكم انها فقط 35).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top