Frage

Ich brauche eine Figur zu berechnen, die zwischen zwei Daten an den nächsten Ort Anzahl der Monate entspricht. Doch die Standard-SAS-Funktion (INTCK) ist nicht darauf ausgerichtet Tag ihrer Datum Parameter zu berücksichtigen (zB Code unten löst auf 0, wenn ich es brauche, um 1 abzurunden).

Was ist der ‚sauberste‘ Weg, um dieses Problem zu lösen?

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

EDIT:. Antwort auf Martins Kommentar

Ich würde Runde 0 Monate - Ich glaube nicht, die Grenze relevant ist. Die Funktion ich versuche zu replizieren (NEAREST_MONTHS) stammt aus DCS (Sungard Prophet Anwendung). Bin jetzt die Chance warten einige Tests in der Anwendung auszuführen sich um mehr darüber zu verstehen, wie es behandelt Daten (wird Ergebnisse Post zurück hier)).

Die Hilfedatei enthält folgende Komponenten: Kategorie Datum

Beschreibung

Gibt die Differenz zwischen zwei Daten zur nächsten Anzahl von Monaten. Wenn das zweite Datum später als der erste Zeitpunkt ist, dann wird 0 zurückgegeben.

Syntax

NEAREST_MONTHS (Later_Date, Earlier_Date)

Rückgabetyp Integer

Beispiele

NEAREST_MONTHS (date1, date2) Gibt 8, wenn date1 ist 20/3/1997 und date2 ist 23/7/1996

NEAREST_MONTHS (date1, date2) Liefert 26, wenn date1 ist 20/3/1997 und date2 ist 1995.01.02

War es hilfreich?

Lösung

Ich schrieb dies als eine Funktion, die ich berechnet auf die gleiche Weise wie die DCS-Anwendung denken. Es verwendet einige Features, die 9.2 einschließlich kontinuierlichen Ausrichtungen in Daten SAS in der Version neu sind. Es funktioniert auch vorwärts oder rückwärts in der Zeit (d ergibt eine negative ganze Zahl, wenn earlier_date nach later_date ist). Früher habe ich mehr als 15 Tage über das Intervall als Cutoff auf den nächsten Monat abzurunden, aber Sie können diese zwicken, wenn Sie es vorziehen.

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;

Dies ergibt das gleiche wie Ihre Referenz:

x=8
x=26

Andere Tipps

Sie könnten INTNX verwenden, um zu sehen, ob auf- oder abrunden, z.


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;

Wenn Sie einen Monat definieren 30 Tage zu sein, würden Sie 15 Tage runden oder weniger bis auf 0 Monate und 16 Tage oder mehr bis zu 1 Monat. Dies kann durch folgendes erreicht werden:

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;

Sie könnte auch den Ansatz, um die vollen Monate zu zählen ( „first erste zum letzten 1.“) im Intervall, und dann alle verbleibenden Tage summieren sich zu sehen, ob sie 0 aufsummieren zu, 1 oder 2 Monate. Wie folgt aus:

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;

Die erste Methode ist einfacher zu verstehen und zu pflegen, aber die zweite ist genauer für große Intervalle (01FEB06 bis 01FEB09 36 Monate, aber Methode 1 werden Ihnen sagen, es ist nur 35).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top