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

发布于 2024-07-25 15:14:37 字数 814 浏览 3 评论 0原文

我需要计算一个数字,该数字等于两个日期之间“最近”的月份数。 然而,标准 SAS 函数 (INTCK) 不适合考虑其日期参数的 DAY(例如,当我需要四舍五入到 1 时,下面的代码解析为 0)。

解决这个问题的“最巧妙”方法是什么?

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

编辑:对马丁斯评论的回应。

我会四舍五入到 0 个月 - 我认为边界不相关。 我尝试复制的函数 (NEAREST_MONTHS) 来自 DCS(Sungard 先知应用程序)。 我现在正在等待有机会在应用程序本身中执行一些测试,以了解更多有关它如何处理日期的信息(将在此处发布结果)。

帮助文件包含以下内容: 类别 日期

描述

返回两个日期之间的差值(最接近的月数)。 如果第二个日期晚于第一个日期,则返回 0。

语法

NEAREST_MONTHS(Later_Date, Early_Date)

返回类型 整数

示例

NEAREST_MONTHS(date1, date2) 如果 date1 为 20/3/1997 并且 date2 为 23/7/1996

NEAREST_MONTHS(date1, date2), 则返回 8 如果 date1 为 20/3/1997 并且 date2 为 1/2/1995,则返回 26

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

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. The function I am trying to replicate (NEAREST_MONTHS) comes from DCS (Sungard prophet application). 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.

Syntax

NEAREST_MONTHS(Later_Date, Earlier_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)
Returns 26 if date1 is 20/3/1997 and date2 is 1/2/1995

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

韬韬不绝 2024-08-01 15:14:37

我将其编写为一个函数,我认为该函数的计算方式与 DCS 应用程序相同。 它使用 SAS 9.2 版中的一些新增功能,包括日期的连续对齐。 它还可以在时间上向前或向后工作(即,如果 Early_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

I wrote this as a function that I think calculates in the same way as the DCS application. It uses some features that are new to SAS in version 9.2 including continuous alignments in dates. It also works forwards or backwards in time (i.e gives a negative integer if earlier_date is after 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.

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
⊕婉儿 2024-08-01 15:14:37

您可以使用 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;

You could use INTNX to see whether to round up or down, e.g.


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;
往日 2024-08-01 15:14:37

如果将一个月定义为 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;

您还可以采用该方法来计算间隔中的完整月份(“第一个到最后一个”),然后将任何剩余天数相加,看看它们的总和是否为 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 个月)。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文