2009-06-25 2 views
1

Мне нужно рассчитать цифру, которая соответствует «ближайшему» числу месяцев между двумя датами. Однако стандартная функция SAS (INTCK) не предназначена для рассмотрения ДНЯ его параметров даты (например, код ниже разрешает 0, когда мне нужно округлить до 1).Вопрос SAS DATE - расчет «БЛИЖАЙШИЙ МЕСЯЦ»

Каков наилучший способ решения этой проблемы?

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

EDIT: ответ на комментарий Мартинса.

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

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

Описание

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

Синтаксис

NEAREST_MONTHS (Later_Date, Earlier_Date)

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

Примеры

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

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

+0

Это сложно, так как вы на самом деле не определить свои правила округления. Например, хотите ли вы округлить интервал между 30APR09 и 01MAY09 до 1 месяца, так как он пересекает границу между двумя разными месяцами или вы будете округлять ее до 0 месяцев, так как это всего лишь однодневный интервал? –

ответ

2

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

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

Ваш код оценивает интервал между 30APR09 и 01MAY09 до 1 месяца, но так как это всего лишь 1 день, я лично обойду его до 0 месяцев. Он также оценивает интервал между 30APR09 и 01JUN09 до 2 месяцев, но я бы обошел его до 1 месяца, так как он составляет 1 месяц и 1 день. –

2

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

Смежные вопросы