SAS DATE выпуск - расчет "Ближайший месяц" - PullRequest
1 голос
/ 25 июня 2009

Мне нужно рассчитать число, которое соответствует «ближайшему» числу месяцев между двумя датами. Однако стандартная функция SAS (INTCK) не предназначена для учета ДНЯ ее параметров даты (например, приведенный ниже код преобразуется в 0, когда мне нужно округлить до 1).

Каков «изощренный» способ решения этой проблемы?

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

РЕДАКТИРОВАТЬ: ответ на комментарий Мартинс.

Я бы округлил до 0 месяцев - я не думаю, что граница актуальна. Функция, которую я пытаюсь воспроизвести (NEAREST_MONTHS), исходит от DCS (приложения Sungard Prophet). Сейчас я жду возможности провести некоторое тестирование в самом приложении, чтобы лучше понять, как оно обрабатывает даты (опубликует результаты здесь)).

Файл справки содержит следующее: категория Дата

Описание

Возвращает разницу между двумя датами с точностью до ближайшего числа месяцев. Если вторая дата позже первой, возвращается 0.

Синтаксис

NEAREST_MONTHS (Later_Date, Earlylier_Date)

Тип возврата Целое число

Примеры * * тысяча двадцать-два

NEAREST_MONTHS (дата1, дата2) Возвращает 8, если date1 - 20/3/1997, а date2 - 23/7/1996

NEAREST_MONTHS (дата1, дата2) Возвращает 26, если date1 - 20/3/1997, а date2 - 1/2/1995

Ответы [ 3 ]

2 голосов
/ 26 июня 2009

Если вы определите месяц как 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).

2 голосов
/ 04 августа 2009

Я написал это как функцию, которая, как мне кажется, рассчитывается так же, как приложение DCS. Он использует некоторые функции, которые являются новыми для SAS в версии 9.2, включая непрерывное выравнивание по датам. Это также работает вперед или назад во времени (то есть дает отрицательное целое число, если ранее_дата после более поздней_даты). Я использовал более 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
2 голосов
/ 25 июня 2009

Вы можете использовать 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;
...