简体   繁体   English

SAS 日期问题 - 计算“最近的月份”

[英]SAS DATE issue - calculating “NEAREST MONTH”

I need to calculate a figure which equates to the 'nearest' number of months between two dates.我需要计算一个数字,它等于两个日期之间“最近”的月数。 However the standard SAS function ( INTCK ) is not geared to consider the DAY of its date parameters (eg code below resolves to 0 when I need it to round to 1).然而,标准 SAS 函数( INTCK )并不适合考虑其日期参数的 DAY (例如,当我需要将其舍入为 1 时,下面的代码解析为 0)。

What is the 'neatest' way of resolving this issue?解决此问题的“最简洁”方法是什么?

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

EDIT: response to Martins comment.编辑:对马丁斯评论的回应。

I would round to 0 months - I don't think the border is relevant.我会舍入到 0 个月 - 我认为边界无关紧要。 The function I am trying to replicate ( NEAREST_MONTHS ) comes from DCS (Sungard prophet application).我试图复制的函数( NEAREST_MONTHS )来自 DCS(Sungard 先知应用程序)。 I am now awaiting the chance to perform some testing within the application itself to understand more about how it treats dates (will post results back here ).我现在正在等待有机会在应用程序本身内执行一些测试,以了解有关它如何处理日期的更多信息(将在此处发布结果)。

The help file contains the following: Category Date帮助文件包含以下内容: 类别 日期

Description描述

Returns the difference between two dates to the nearest number of months.将两个日期之间的差值返回到最接近的月数。 If the second date is later than the first date then 0 is returned.如果第二个日期晚于第一个日期,则返回 0。

Syntax句法

NEAREST_MONTHS(Later_Date, Earlier_Date) NEAREST_MONTHS(Later_Date, Early_Date)

Return Type Integer返回类型整数

Examples例子

NEAREST_MONTHS(date1, date2) Returns 8 if date1 is 20/3/1997 and date2 is 23/7/1996 NEAREST_MONTHS(date1, date2) 如果 date1 是 20/3/1997 并且 date2 是 23/7/1996,则返回 8

NEAREST_MONTHS(date1, date2) Returns 26 if date1 is 20/3/1997 and date2 is 1/2/1995 NEAREST_MONTHS(date1, date2) 如果 date1 是 20/3/1997 并且 date2 是 1/2/1995,则返回 26

You could use INTNX to see whether to round up or down, eg您可以使用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;

If you define a month to be 30 days, you would round 15 days or less down to 0 months, and 16 days or more up to 1 month.如果您将一个月定义为 30 天,则您会将 15 天或更短的天数向下舍入为 0 个月,将 16 天或更长时间向下舍入为 1 个月。 This can be achieved by the following:这可以通过以下方式实现:

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;

You could also take the approach to count the full months ("first 1st to last 1st") in the interval, and then add up any remaining days to see if they sum up to 0, 1 or 2 months.您还可以采用这种方法来计算间隔中的完整月份(“第 1 天到最后 1 天”),然后将剩余的天数相加,看看它们的总和是 0、1 还是 2 个月。 Like this:像这样:

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;

The first method is easier to understand and maintain, but the second is more accurate for large intervals (01FEB06 to 01FEB09 is 36 months, but method 1 will tell you it's only 35).第一种方法更容易理解和维护,但第二种方法对于大间隔更准确(01FEB06 到 01FEB09 是 36 个月,但方法 1 会告诉你它只有 35 个月)。

I wrote this as a function that I think calculates in the same way as the DCS application.我把它写成一个函数,我认为它的计算方式与 DCS 应用程序相同。 It uses some features that are new to SAS in version 9.2 including continuous alignments in dates.它使用了 SAS 9.2 版中的一些新功能,包括日期的连续对齐。 It also works forwards or backwards in time (ie gives a negative integer if earlier_date is after later_date).它也可以在时间上向前或向后工作(即,如果 early_date 在 later_date 之后,则给出一个负整数)。 I used more than 15 days beyond the interval as the cutoff to round to the next month but you can tweak this if you prefer.我使用超过间隔超过 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;

This gives the same as your reference:这与您的参考相同:

x=8
x=26

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM