Question

Je dois calculer un chiffre qui correspond au nombre de mois le plus proche entre deux dates. Cependant, la fonction SAS standard (INTCK) n’est pas conçue pour prendre en compte le JOUR de ses paramètres de date (par exemple, le code ci-dessous est ramené à 0 lorsque j’ai besoin de l’arrondir à 1).

Quel est le moyen le plus "propre" de résoudre ce problème?

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

EDIT: réponse au commentaire de Martins.

J'arrondirais à 0 mois - je ne pense pas que la frontière soit pertinente. La fonction que je tente de reproduire (NEAREST_MONTHS) provient de DCS (application Sungard Prophet). J'attends maintenant la possibilité d'effectuer des tests dans l'application elle-même pour en savoir plus sur la façon dont elle traite les dates (les résultats seront affichés ici).

Le fichier d'aide contient les éléments suivants: Catégorie Date

Description

Renvoie la différence entre deux dates au nombre de mois le plus proche. Si la deuxième date est postérieure à la première date, 0 est renvoyé.

Syntaxe

NEAREST_MONTHS (Later_Date, Earlier_Date)

Type de retour Entier

Exemples

NEAREST_MONTHS (date1, date2) Retourne 8 si date1 est le 20/3/1997 et date2 est le 23/7/1996

NEAREST_MONTHS (date1, date2) Retourne 26 si date1 est le 20/3/1997 et date2 est le 1/2/1995

Était-ce utile?

La solution

J'ai écrit cela comme une fonction qui, à mon avis, se calcule de la même manière que l'application DCS. Il utilise certaines fonctionnalités nouvelles de SAS dans la version 9.2, notamment les alignements continus dans les dates. Cela fonctionne aussi en avant ou en arrière dans le temps (c.-à-d. Donne un entier négatif si date_avant est après la date plus tard). J'ai utilisé plus de 15 jours au-delà de l'intervalle comme limite pour arrondir au mois prochain, mais vous pouvez modifier cela si vous préférez.

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;

Cela donne la même chose que votre référence:

x=8
x=26

Autres conseils

Vous pouvez utiliser INTNX pour savoir s'il faut arrondir de haut en bas, par exemple

.

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;

Si vous définissez un mois comme étant 30 jours, vous arrondissez 15 jours ou moins à 0 mois et 16 jours ou plus à 1 mois. Ceci peut être réalisé de la manière suivante:

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;

Vous pouvez également choisir de compter les mois complets ("premier, premier, dernier, dernier") de l'intervalle, puis d'additionner les jours restants pour déterminer s'ils totalisent 0, 1 ou 2 mois. Comme ceci:

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;

La première méthode est plus facile à comprendre et à gérer, mais la seconde est plus précise pour les grands intervalles (01FEB06 à 01FEB09 est de 36 mois, mais la méthode 1 vous dira qu’il n’ya que 35 ans.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top