2009-06-25 7 views
1

Ich muss eine Zahl berechnen, die der "nächsten" Anzahl von Monaten zwischen zwei Daten entspricht. Die Standard-SAS-Funktion (INTCK) ist jedoch nicht darauf ausgelegt, den DAY seiner Datumsparameter zu berücksichtigen (z. B. Code unten löst sich auf 0 auf, wenn ich ihn auf 1 runden möchte).SAS DATE Ausgabe - Berechnung "NEAREST MONTH"

Was ist der "beste" Weg zur Lösung dieses Problems?

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

EDIT: Antwort auf Martins Kommentar.

Ich würde auf 0 Monate runden - ich glaube nicht, dass die Grenze relevant ist. Die Funktion, die ich versuche zu replizieren (NEAREST_MONTHS) stammt von DCS (Sungard Prophet Application). Ich warte jetzt auf die Möglichkeit, einige Tests innerhalb der Anwendung selbst durchzuführen, um mehr darüber zu erfahren, wie es mit Daten umgeht (wird die Ergebnisse hier zurückgeben)).

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 das erste Datum ist, wird 0 zurückgegeben.

Syntax

NEAREST_MONTHS (Later_Date, Earlier_Date)

Rückgabetyp Integer

Beispiele

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

NEAREST_MONTHS (date1, date2) Gibt 26 zurück, wenn Datum1 ist 20/3/1997 und Datum2 ist 1/2/1995

+0

Diese heikel ist, da Sie wirklich für die Rundung nicht Ihre Regeln definieren. Möchten Sie beispielsweise das Intervall zwischen 30.04.09 und 01.May09 auf 1 Monat runden, da es die Grenze zwischen 2 verschiedenen Monaten überschreitet, oder würden Sie es auf 0 Monate runden, da es nur ein 1-Tages-Intervall ist? –

Antwort

2

Ich schrieb dies als eine Funktion, die ich denke, berechnet auf die gleiche Weise wie die DCS-Anwendung. Es verwendet einige Funktionen, die in Version 9.2 für SAS neu sind, einschließlich kontinuierlicher Alignments in Datumsangaben. Es arbeitet auch vorwärts oder rückwärts in der Zeit (d. H. Gibt eine negative ganze Zahl aus, wenn das frühere Datum nach dem späteren Datum liegt). Ich habe mehr als 15 Tage nach dem Intervall als Cutoff verwendet, um auf den nächsten Monat zu kommen, aber Sie können dies optimieren, wenn Sie bevorzugen.

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 
2

Sie können INTNX verwenden, um zu sehen, ob auf- oder abzurunden, 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; 
+0

Ihr Code bewertet das Intervall zwischen 30APR09 und 01MAY09 bis 1 Monat, aber da es nur 1 Tag ist, würde ich persönlich auf 0 Monate runden. Es bewertet auch das Intervall zwischen 30APR09 und 01JUN09 zu 2 Monaten, aber ich würde es auf 1 Monat runden, da es 1 Monat und 1 Tag ist. –

2

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

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 auch den Ansatz könnte die volle Monate („first ersten zum letzten 1.“) im Intervall zu zählen, und dann alle verbleibenden Tage summieren sich zu sehen, ob sie summieren sich zu 0, 1 oder 2 Monaten. So:

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 beträgt 36 Monate, aber Methode 1 werden Ihnen sagen, es ist nur 35).