[Scipy-svn] r2867 - trunk/Lib/sandbox/timeseries/src

scipy-svn at scipy.org scipy-svn at scipy.org
Fri Mar 23 11:00:01 EDT 2007


Author: mattknox_ca
Date: 2007-03-23 09:59:50 -0500 (Fri, 23 Mar 2007)
New Revision: 2867

Modified:
   trunk/Lib/sandbox/timeseries/src/cseries.c
Log:
added support for quarterly frequencies with different year ends

Modified: trunk/Lib/sandbox/timeseries/src/cseries.c
===================================================================
--- trunk/Lib/sandbox/timeseries/src/cseries.c	2007-03-22 13:54:08 UTC (rev 2866)
+++ trunk/Lib/sandbox/timeseries/src/cseries.c	2007-03-23 14:59:50 UTC (rev 2867)
@@ -20,7 +20,52 @@
 #define FR_ANNOCT  1010  /* Annual - October year end*/
 #define FR_ANNNOV  1011  /* Annual - November year end*/
 
-#define FR_QTR  2000  /* Quarterly */
+/* The standard quarterly frequencies. Year is determined by what year the end
+   month lies in. */
+#define FR_QTR  2000       /* Quarterly - December year end (default quarterly) */
+#define FR_QTRDEC  FR_QTR  /* Quarterly - December year end */
+#define FR_QTRJAN  2001    /* Quarterly - January year end */
+#define FR_QTRFEB  2002    /* Quarterly - February year end */
+#define FR_QTRMAR  2003    /* Quarterly - March year end */
+#define FR_QTRAPR  2004    /* Quarterly - April year end */
+#define FR_QTRMAY  2005    /* Quarterly - May year end */
+#define FR_QTRJUN  2006    /* Quarterly - June year end */
+#define FR_QTRJUL  2007    /* Quarterly - July year end */
+#define FR_QTRAUG  2008    /* Quarterly - August year end */
+#define FR_QTRSEP  2009    /* Quarterly - September year end */
+#define FR_QTROCT  2010    /* Quarterly - October year end */
+#define FR_QTRNOV  2011    /* Quarterly - November year end */
+
+/* End period based quarterly frequencies. Year is determined by what year the
+   end month lies in. */
+#define FR_QTREDEC  FR_QTRDEC  /* Quarterly - December year end*/
+#define FR_QTREJAN  FR_QTRJAN  /* Quarterly - January year end*/
+#define FR_QTREFEB  FR_QTRFEB  /* Quarterly - February year end*/
+#define FR_QTREMAR  FR_QTRMAR  /* Quarterly - March year end*/
+#define FR_QTREAPR  FR_QTRAPR  /* Quarterly - April year end*/
+#define FR_QTREMAY  FR_QTRMAY  /* Quarterly - May year end*/
+#define FR_QTREJUN  FR_QTRJUN  /* Quarterly - June year end*/
+#define FR_QTREJUL  FR_QTRJUL  /* Quarterly - July year end*/
+#define FR_QTREAUG  FR_QTRAUG  /* Quarterly - August year end*/
+#define FR_QTRESEP  FR_QTRSEP  /* Quarterly - September year end*/
+#define FR_QTREOCT  FR_QTROCT  /* Quarterly - October year end*/
+#define FR_QTRENOV  FR_QTRNOV  /* Quarterly - November year end*/
+
+/* Starting period based quarterly frequencies. Year is determined by what year
+   the starting month lies in. */
+#define FR_QTRSDEC  FR_QTRDEC+12  /* Quarterly - December year end*/
+#define FR_QTRSJAN  FR_QTRJAN+12  /* Quarterly - January year end*/
+#define FR_QTRSFEB  FR_QTRFEB+12  /* Quarterly - February year end*/
+#define FR_QTRSMAR  FR_QTRMAR+12  /* Quarterly - March year end*/
+#define FR_QTRSAPR  FR_QTRAPR+12  /* Quarterly - April year end*/
+#define FR_QTRSMAY  FR_QTRMAY+12  /* Quarterly - May year end*/
+#define FR_QTRSJUN  FR_QTRJUN+12  /* Quarterly - June year end*/
+#define FR_QTRSJUL  FR_QTRJUL+12  /* Quarterly - July year end*/
+#define FR_QTRSAUG  FR_QTRAUG+12  /* Quarterly - August year end*/
+#define FR_QTRSSEP  FR_QTRSEP+12  /* Quarterly - September year end*/
+#define FR_QTRSOCT  FR_QTROCT+12  /* Quarterly - October year end*/
+#define FR_QTRSNOV  FR_QTRNOV+12  /* Quarterly - November year end*/
+
 #define FR_MTH  3000  /* Monthly */
 
 #define FR_WK   4000  /* Weekly */
@@ -56,6 +101,8 @@
     int from_a_year_end; //month the year ends on in the "from" frequency
     int to_a_year_end; //month the year ends on in the "to" frequency
 
+    int from_q_year_end; //month the year ends on in the "from" frequency
+    int to_q_year_end; //month the year ends on in the "to" frequency
 };
 
 static struct asfreq_info NULL_AF_INFO;
@@ -409,6 +456,7 @@
     return -1;
 }
 
+static int monthToQuarter(int month) { return ((month-1)/3)+1; }
 
 /* Sets the date part of the date_info struct using the indicated
    calendar.
@@ -474,7 +522,7 @@
         }
 
         dinfo->month = month;
-        dinfo->quarter = ((month-1)/3)+1;
+        dinfo->quarter = monthToQuarter(month);
         dinfo->day = dayoffset - month_offset[leap][month-1];
     }
 
@@ -601,15 +649,35 @@
     else { return (long)(dinfo.year); }
 }
 
-
-static long asfreq_DtoQ(long fromDate, char relation, struct asfreq_info *af_info) {
-
+static long DtoQ_yq(long fromDate, struct asfreq_info *af_info,
+                              int *year, int *quarter) {
     struct date_info dinfo;
     if (dInfoCalc_SetFromAbsDate(&dinfo, fromDate,
                     GREGORIAN_CALENDAR)) return INT_ERR_CODE;
-    return (long)((dinfo.year - 1) * 4 + dinfo.quarter);
+    if (af_info->to_q_year_end != 12) {
+        dinfo.month -= af_info->to_q_year_end;
+        if (dinfo.month <= 0) { dinfo.month += 12; }
+        else { dinfo.year += 1; }
+        dinfo.quarter = monthToQuarter(dinfo.month);
+    }
+
+    *year = dinfo.year;
+    *quarter = dinfo.quarter;
+
+    return 0;
 }
 
+
+static long asfreq_DtoQ(long fromDate, char relation, struct asfreq_info *af_info) {
+
+    int year, quarter;
+
+    if (DtoQ_yq(fromDate, af_info, &year, &quarter) == INT_ERR_CODE)
+    { return INT_ERR_CODE; }
+
+    return (long)((year - 1) * 4 + quarter);
+}
+
 static long asfreq_DtoM(long fromDate, char relation, struct asfreq_info *af_info) {
 
     struct date_info dinfo;
@@ -673,7 +741,7 @@
 static long asfreq_StoA(long fromDate, char relation, struct asfreq_info *af_info)
     { return asfreq_DtoA(asfreq_StoD(fromDate, relation, &NULL_AF_INFO), relation, af_info); }
 static long asfreq_StoQ(long fromDate, char relation, struct asfreq_info *af_info)
-    { return asfreq_DtoQ(asfreq_StoD(fromDate, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); }
+    { return asfreq_DtoQ(asfreq_StoD(fromDate, relation, &NULL_AF_INFO), relation, af_info); }
 static long asfreq_StoM(long fromDate, char relation, struct asfreq_info *af_info)
     { return asfreq_DtoM(asfreq_StoD(fromDate, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); }
 static long asfreq_StoW(long fromDate, char relation, struct asfreq_info *af_info)
@@ -695,7 +763,7 @@
 static long asfreq_TtoA(long fromDate, char relation, struct asfreq_info *af_info)
     { return asfreq_DtoA(asfreq_TtoD(fromDate, relation, &NULL_AF_INFO), relation, af_info); }
 static long asfreq_TtoQ(long fromDate, char relation, struct asfreq_info *af_info)
-    { return asfreq_DtoQ(asfreq_TtoD(fromDate, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); }
+    { return asfreq_DtoQ(asfreq_TtoD(fromDate, relation, &NULL_AF_INFO), relation, af_info); }
 static long asfreq_TtoM(long fromDate, char relation, struct asfreq_info *af_info)
     { return asfreq_DtoM(asfreq_TtoD(fromDate, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); }
 static long asfreq_TtoW(long fromDate, char relation, struct asfreq_info *af_info)
@@ -719,7 +787,7 @@
 static long asfreq_HtoA(long fromDate, char relation, struct asfreq_info *af_info)
     { return asfreq_DtoA(asfreq_HtoD(fromDate, relation, &NULL_AF_INFO), relation, af_info); }
 static long asfreq_HtoQ(long fromDate, char relation, struct asfreq_info *af_info)
-    { return asfreq_DtoQ(asfreq_HtoD(fromDate, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); }
+    { return asfreq_DtoQ(asfreq_HtoD(fromDate, relation, &NULL_AF_INFO), relation, af_info); }
 static long asfreq_HtoM(long fromDate, char relation, struct asfreq_info *af_info)
     { return asfreq_DtoM(asfreq_HtoD(fromDate, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); }
 static long asfreq_HtoW(long fromDate, char relation, struct asfreq_info *af_info)
@@ -746,7 +814,7 @@
     { return asfreq_DtoA(asfreq_BtoD(fromDate, relation, &NULL_AF_INFO), relation, af_info); }
 
 static long asfreq_BtoQ(long fromDate, char relation, struct asfreq_info *af_info)
-    { return asfreq_DtoQ(asfreq_BtoD(fromDate, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); }
+    { return asfreq_DtoQ(asfreq_BtoD(fromDate, relation, &NULL_AF_INFO), relation, af_info); }
 
 static long asfreq_BtoM(long fromDate, char relation, struct asfreq_info *af_info)
     { return asfreq_DtoM(asfreq_BtoD(fromDate, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); }
@@ -773,12 +841,12 @@
 static long asfreq_WtoA(long fromDate, char relation, struct asfreq_info *af_info) {
     return asfreq_DtoA(asfreq_WtoD(fromDate, 'A', af_info), relation, af_info); }
 static long asfreq_WtoQ(long fromDate, char relation, struct asfreq_info *af_info) {
-    return asfreq_DtoQ(asfreq_WtoD(fromDate, 'A', af_info), relation, &NULL_AF_INFO); }
+    return asfreq_DtoQ(asfreq_WtoD(fromDate, 'A', af_info), relation, af_info); }
 static long asfreq_WtoM(long fromDate, char relation, struct asfreq_info *af_info) {
     return asfreq_DtoM(asfreq_WtoD(fromDate, 'A', af_info), relation, &NULL_AF_INFO); }
 
 static long asfreq_WtoW(long fromDate, char relation, struct asfreq_info *af_info)
-    { return asfreq_DtoW(asfreq_WtoD(fromDate, relation, af_info), relation, &NULL_AF_INFO); }
+    { return asfreq_DtoW(asfreq_WtoD(fromDate, relation, af_info), relation, af_info); }
 
 static long asfreq_WtoB(long fromDate, char relation, struct asfreq_info *af_info) {
 
@@ -820,14 +888,10 @@
 }
 
 static long asfreq_MtoA(long fromDate, char relation, struct asfreq_info *af_info) {
-    long year = (fromDate - 1) / 12 + 1;
-    long month = fromDate - (year - 1)*12;
-    if (month > af_info->to_a_year_end) { return year + 1; }
-    else { return year; }
-}
+    return asfreq_DtoA(asfreq_MtoD(fromDate, 'A', &NULL_AF_INFO), relation, af_info); }
 
-static long asfreq_MtoQ(long fromDate, char relation, struct asfreq_info *af_info)
-    { return (fromDate - 1) / 3 + 1; }
+static long asfreq_MtoQ(long fromDate, char relation, struct asfreq_info *af_info) {
+    return asfreq_DtoQ(asfreq_MtoD(fromDate, 'A', &NULL_AF_INFO), relation, af_info); }
 
 static long asfreq_MtoW(long fromDate, char relation, struct asfreq_info *af_info)
     { return asfreq_DtoW(asfreq_MtoD(fromDate, relation, &NULL_AF_INFO), relation, af_info); }
@@ -851,9 +915,16 @@
 
 //************ FROM QUARTERLY ***************
 
-static void QtoD_ym(long fromDate, long *y, long *m) {
+static void QtoD_ym(long fromDate, long *y, long *m, struct asfreq_info *af_info) {
+
     *y = (fromDate - 1) / 4 + 1;
     *m = (fromDate + 4) * 3 - 12 * (*y) - 2;
+
+    if (af_info->from_q_year_end != 12) {
+        *m += af_info->from_q_year_end;
+        if (*m > 12) { *m -= 12; }
+        else { *y -= 1; }
+    }
 }
 
 static long asfreq_QtoD(long fromDate, char relation, struct asfreq_info *af_info) {
@@ -861,35 +932,32 @@
     long y, m, absdate;
 
     if (relation == 'B') {
-        QtoD_ym(fromDate, &y, &m);
+        QtoD_ym(fromDate, &y, &m, af_info);
         if ((absdate = absdate_from_ymd(y, m, 1)) == INT_ERR_CODE) return INT_ERR_CODE;
         return absdate;
     } else {
-        QtoD_ym(fromDate+1, &y, &m);
+        QtoD_ym(fromDate+1, &y, &m, af_info);
         if ((absdate = absdate_from_ymd(y, m, 1)) == INT_ERR_CODE) return INT_ERR_CODE;
         return absdate - 1;
     }
 }
 
+static long asfreq_QtoQ(long fromDate, char relation, struct asfreq_info *af_info)
+    { return asfreq_DtoQ(asfreq_QtoD(fromDate, relation, af_info), relation, af_info); }
+
 static long asfreq_QtoA(long fromDate, char relation, struct asfreq_info *af_info) {
-    long year = (fromDate - 1) / 4 + 1;
-    long quarter = fromDate - (year - 1)*4;
-    if (quarter > af_info->to_a_year_end) { return year + 1; }
-    else { return year; }
-}
+    return asfreq_DtoA(asfreq_QtoD(fromDate, relation, af_info), relation, af_info); }
 
 static long asfreq_QtoM(long fromDate, char relation, struct asfreq_info *af_info) {
-    if (relation == 'B') { return fromDate * 3 - 2; }
-    else {                 return fromDate  * 3; }
-}
+    return asfreq_DtoM(asfreq_QtoD(fromDate, relation, af_info), relation, &NULL_AF_INFO); }
 
 static long asfreq_QtoW(long fromDate, char relation, struct asfreq_info *af_info)
-    { return asfreq_DtoW(asfreq_QtoD(fromDate, relation, &NULL_AF_INFO), relation, af_info); }
+    { return asfreq_DtoW(asfreq_QtoD(fromDate, relation, af_info), relation, af_info); }
 
 static long asfreq_QtoB(long fromDate, char relation, struct asfreq_info *af_info) {
 
     struct date_info dinfo;
-    if (dInfoCalc_SetFromAbsDate(&dinfo, asfreq_QtoD(fromDate, relation, &NULL_AF_INFO),
+    if (dInfoCalc_SetFromAbsDate(&dinfo, asfreq_QtoD(fromDate, relation, af_info),
                     GREGORIAN_CALENDAR)) return INT_ERR_CODE;
 
     if (relation == 'B') { return DtoB_WeekendToMonday(dinfo.absdate, dinfo.day_of_week); }
@@ -898,11 +966,11 @@
 
 
 static long asfreq_QtoH(long fromDate, char relation, struct asfreq_info *af_info)
-    { return asfreq_DtoH(asfreq_QtoD(fromDate, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); }
+    { return asfreq_DtoH(asfreq_QtoD(fromDate, relation, af_info), relation, &NULL_AF_INFO); }
 static long asfreq_QtoT(long fromDate, char relation, struct asfreq_info *af_info)
-    { return asfreq_DtoT(asfreq_QtoD(fromDate, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); }
+    { return asfreq_DtoT(asfreq_QtoD(fromDate, relation, af_info), relation, &NULL_AF_INFO); }
 static long asfreq_QtoS(long fromDate, char relation, struct asfreq_info *af_info)
-    { return asfreq_DtoS(asfreq_QtoD(fromDate, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); }
+    { return asfreq_DtoS(asfreq_QtoD(fromDate, relation, af_info), relation, &NULL_AF_INFO); }
 
 
 //************ FROM ANNUAL ***************
@@ -925,62 +993,26 @@
     return absdate + final_adj;
 }
 
-static long asfreq_AtoQ(long fromDate, char relation, struct asfreq_info *af_info) {
+static long asfreq_AtoA(long fromDate, char relation, struct asfreq_info *af_info)
+    { return asfreq_DtoA(asfreq_AtoD(fromDate, relation, af_info), relation, af_info); }
 
-    long quarter = asfreq_MtoQ(af_info->from_a_year_end, 'B', &NULL_AF_INFO);
+static long asfreq_AtoQ(long fromDate, char relation, struct asfreq_info *af_info)
+    { return asfreq_DtoQ(asfreq_AtoD(fromDate, relation, af_info), relation, af_info); }
 
-    if (relation == 'B') {
-        return fromDate * 4 - 3 - (4 - quarter);
-    } else {
-        return fromDate * 4 - (4 - quarter);
-    }
-}
+static long asfreq_AtoM(long fromDate, char relation, struct asfreq_info *af_info)
+    { return asfreq_DtoM(asfreq_AtoD(fromDate, relation, af_info), relation, af_info); }
 
-static long asfreq_AtoM(long fromDate, char relation, struct asfreq_info *af_info) {
-    if (relation == 'B') {
-        return fromDate * 12 - 11 - (12 - af_info->from_a_year_end);
-    } else {
-        return fromDate * 12 - (12 - af_info->from_a_year_end);
-    }
-}
-
 static long asfreq_AtoW(long fromDate, char relation, struct asfreq_info *af_info)
     { return asfreq_DtoW(asfreq_AtoD(fromDate, relation, af_info), relation, af_info); }
 
 static long asfreq_AtoB(long fromDate, char relation, struct asfreq_info *af_info) {
 
-    long year;
-    int month = (af_info->from_a_year_end + 1) % 12;
+    struct date_info dinfo;
+    if (dInfoCalc_SetFromAbsDate(&dinfo, asfreq_AtoD(fromDate, relation, af_info),
+                    GREGORIAN_CALENDAR)) return INT_ERR_CODE;
 
-    struct date_info dailyDate;
-
-    if (relation == 'B') {
-
-        if (af_info->from_a_year_end == 12) {year = fromDate;}
-        else {year = fromDate - 1;}
-
-        if (dInfoCalc_SetFromDateAndTime(&dailyDate,
-                        year,month,1, 0, 0, 0,
-                        GREGORIAN_CALENDAR)) return INT_ERR_CODE;
-        return DtoB_WeekendToMonday(dailyDate.absdate, dailyDate.day_of_week);
-    } else {
-        long absdate;
-
-        if (af_info->from_a_year_end == 12) {year = fromDate+1;}
-        else {year = fromDate;}
-
-        if (dInfoCalc_SetFromDateAndTime(&dailyDate,
-                       year,month,1, 0, 0, 0,
-                       GREGORIAN_CALENDAR)) return INT_ERR_CODE;
-
-        absdate = dailyDate.absdate - 1;
-
-        if(dInfoCalc_SetFromAbsDate(&dailyDate,
-                      absdate,
-                      GREGORIAN_CALENDAR)) return INT_ERR_CODE;
-
-        return DtoB_WeekendToFriday(dailyDate.absdate, dailyDate.day_of_week);
-    }
+    if (relation == 'B') { return DtoB_WeekendToMonday(dinfo.absdate, dinfo.day_of_week); }
+    else                 { return DtoB_WeekendToFriday(dinfo.absdate, dinfo.day_of_week); }
 }
 
 static long asfreq_AtoH(long fromDate, char relation, struct asfreq_info *af_info)
@@ -1007,6 +1039,7 @@
         case FR_ANN:
             switch(toGroup)
             {
+                case FR_ANN: return &asfreq_AtoA;
                 case FR_QTR: return &asfreq_AtoQ;
                 case FR_MTH: return &asfreq_AtoM;
                 case FR_WK: return &asfreq_AtoW;
@@ -1022,6 +1055,7 @@
             switch(toGroup)
             {
                 case FR_ANN: return &asfreq_QtoA;
+                case FR_QTR: return &asfreq_QtoQ;
                 case FR_MTH: return &asfreq_QtoM;
                 case FR_WK: return &asfreq_QtoW;
                 case FR_BUS: return &asfreq_QtoB;
@@ -1251,7 +1285,7 @@
 }
 
 static int calc_a_year_end(int freq, int group) {
-    int result = freq - group;
+    int result = (freq - group) % 12;
     if (result == 0) {return 12;}
     else {return result;}
 }
@@ -1273,6 +1307,10 @@
         case FR_ANN: {
             af_info->from_a_year_end = calc_a_year_end(fromFreq, fromGroup);
         } break;
+        case FR_QTR: {
+            af_info->from_q_year_end = calc_a_year_end(fromFreq, fromGroup);
+        } break;
+
     }
 
     switch(toGroup)
@@ -1283,21 +1321,13 @@
         case FR_ANN: {
             af_info->to_a_year_end = calc_a_year_end(toFreq, toGroup);
         } break;
+        case FR_QTR: {
+            af_info->to_q_year_end = calc_a_year_end(toFreq, toGroup);
+        } break;
     }
 
 }
 
-static int dInfo_year(struct date_info *dateObj)    { return dateObj->year; }
-static int dInfo_quarter(struct date_info *dateObj) { return dateObj->quarter; }
-static int dInfo_month(struct date_info *dateObj)   { return dateObj->month; }
-static int dInfo_day(struct date_info *dateObj)     { return dateObj->day; }
-static int dInfo_day_of_year(struct date_info *dateObj) { return dateObj->day_of_year; }
-static int dInfo_day_of_week(struct date_info *dateObj) { return dateObj->day_of_week; }
-static int dInfo_week(struct date_info *dateObj)     { return dInfoCalc_ISOWeek(dateObj); }
-static int dInfo_hour(struct date_info *dateObj)     { return dateObj->hour; }
-static int dInfo_minute(struct date_info *dateObj)     { return dateObj->minute; }
-static int dInfo_second(struct date_info *dateObj)     { return (int)dateObj->second; }
-
 static double getAbsTime(int freq, long dailyDate, long originalDate) {
 
     long startOfDay, periodsPerDay;
@@ -1361,9 +1391,9 @@
      Py_DECREF(aliases); }
 
 
-static int init_freq_group(int num_items, int num_roots, int group_const,
-                            char item_abbrevs[][2][10], char group_prefixes[][10],
-                            char item_const_names[][10]) {
+static int init_freq_group(int num_items, int num_roots, int base_const,
+                            char item_abbrevs[][2][10], char group_prefixes[][15],
+                            char item_const_names[][15]) {
 
     int i;
 
@@ -1382,8 +1412,8 @@
             PyObject *alias_v1, *alias_v2;
             char *root, *alt;
 
-            if ((root = malloc((26) * sizeof(char))) == NULL) return INT_ERR_CODE;
-            if ((alt = malloc((26) * sizeof(char))) == NULL) return INT_ERR_CODE;
+            if ((root = malloc((30) * sizeof(char))) == NULL) return INT_ERR_CODE;
+            if ((alt = malloc((30) * sizeof(char))) == NULL) return INT_ERR_CODE;
 
             strcpy(root, group_prefixes[j]);
             strcpy(alt, group_prefixes[j]);
@@ -1408,7 +1438,7 @@
             PyTuple_SET_ITEM(aliases, j*k + 1, alias_v2);
         }
 
-        INIT_FREQ(item_const_names[i], group_const+i, aliases);
+        INIT_FREQ(item_const_names[i], base_const+i, aliases);
     }
 
     return 0;
@@ -1440,10 +1470,15 @@
 
 static int build_freq_dict() {
 
-    char ANN_prefixes[8][10] = { "A", "Y", "ANN", "ANNUAL", "ANNUALLY",
+    char ANN_prefixes[8][15] = { "A", "Y", "ANN", "ANNUAL", "ANNUALLY",
                                  "YR", "YEAR", "YEARLY" };
-    char WK_prefixes[4][10] =  { "W", "WK", "WEEK", "WEEKLY" };
 
+    char QTRE_prefixes[8][15] = { "Q", "QTR", "QUARTER", "QUARTERLY", "Q-E",
+                                  "QTR-E", "QUARTER-E", "QUARTERLY-E"};
+    char QTRS_prefixes[4][15] = { "Q-S", "QTR-S", "QUARTER-S", "QUARTERLY-S" };
+
+    char WK_prefixes[4][15] =  { "W", "WK", "WEEK", "WEEKLY" };
+
     /* Note: order of this array must match up with how the Annual
        frequency constants are lined up */
     char month_names[12][2][10] = {
@@ -1460,7 +1495,16 @@
         { "OCT", "OCTOBER" },
         { "NOV", "NOVEMBER" }};
 
-    char ANN_const_names[12][10] = {
+    char day_names[7][2][10] = {
+        { "SUN", "SUNDAY" },
+        { "MON", "MONDAY" },
+        { "TUE", "TUESDAY" },
+        { "WED", "WEDNESDAY" },
+        { "THU", "THURSDAY" },
+        { "FRI", "FRIDAY" },
+        { "SAT", "SATURDAY" }};
+
+    char ANN_const_names[12][15] = {
         "FR_ANNDEC",
         "FR_ANNJAN",
         "FR_ANNFEB",
@@ -1474,16 +1518,35 @@
         "FR_ANNOCT",
         "FR_ANNNOV"};
 
-    char day_names[7][2][10] = {
-        { "SUN", "SUNDAY" },
-        { "MON", "MONDAY" },
-        { "TUE", "TUESDAY" },
-        { "WED", "WEDNESDAY" },
-        { "THU", "THURSDAY" },
-        { "FRI", "FRIDAY" },
-        { "SAT", "SATURDAY" }};
+    char QTRE_const_names[12][15] = {
+        "FR_QTREDEC",
+        "FR_QTREJAN",
+        "FR_QTREFEB",
+        "FR_QTREMAR",
+        "FR_QTREAPR",
+        "FR_QTREMAY",
+        "FR_QTREJUN",
+        "FR_QTREJUL",
+        "FR_QTREAUG",
+        "FR_QTRESEP",
+        "FR_QTREOCT",
+        "FR_QTRENOV"};
 
-    char WK_const_names[7][10] = {
+    char QTRS_const_names[12][15] = {
+        "FR_QTRSDEC",
+        "FR_QTRSJAN",
+        "FR_QTRSFEB",
+        "FR_QTRSMAR",
+        "FR_QTRSAPR",
+        "FR_QTRSMAY",
+        "FR_QTRSJUN",
+        "FR_QTRSJUL",
+        "FR_QTRSAUG",
+        "FR_QTRSSEP",
+        "FR_QTRSOCT",
+        "FR_QTRSNOV"};
+
+    char WK_const_names[7][15] = {
         "FR_WKSUN",
         "FR_WKMON",
         "FR_WKTUE",
@@ -1498,9 +1561,6 @@
     freq_dict_rev = PyDict_New();
     freq_constants = PyDict_New();
 
-    aliases = Py_BuildValue("(ssss)", "Q", "QTR", "QUARTER", "QUARTERLY");
-    INIT_FREQ("FR_QTR", FR_QTR, aliases);
-
     aliases = Py_BuildValue("(ssss)", "M", "MTH", "MONTH", "MONTHLY");
     INIT_FREQ("FR_MTH", FR_MTH, aliases);
 
@@ -1529,6 +1589,18 @@
             return INT_ERR_CODE;
     }
 
+    ADD_FREQ_CONSTANT("FR_QTR", FR_QTR);
+
+    if(init_freq_group(12, 8, FR_QTREDEC,
+        month_names, QTRE_prefixes, QTRE_const_names) == INT_ERR_CODE) {
+            return INT_ERR_CODE;
+    }
+
+    if(init_freq_group(12, 4, FR_QTRSDEC,
+        month_names, QTRS_prefixes, QTRS_const_names) == INT_ERR_CODE) {
+            return INT_ERR_CODE;
+    }
+
     ADD_FREQ_CONSTANT("FR_WK", FR_WK);
 
     if(init_freq_group(7, 4, FR_WK,
@@ -1696,11 +1768,9 @@
                 if (month == def_info) {
                     INIT_ERR(PyExc_ValueError, INSUFFICIENT_MSG);
                 }
-            } else if (self->freq == FR_QTR) {
-                if (quarter == def_info && month == def_info) {
+            } else if (freq_group == FR_QTR) {
+                if (quarter == def_info) {
                     INIT_ERR(PyExc_ValueError, INSUFFICIENT_MSG);
-                } else if (month != def_info) {
-                    quarter = (int)asfreq_MtoQ(month, '-', &NULL_AF_INFO);
                 }
             } else if (self->freq == FR_SEC) {
                 if (month == def_info ||
@@ -1768,8 +1838,15 @@
             self->value = adj_ordinal/7;
         } else if (self->freq == FR_MTH) {
             self->value = (year-1)*12 + month;
-        } else if (self->freq == FR_QTR) {
-            self->value = (year-1)*4 + quarter;
+        } else if (freq_group == FR_QTR) {
+            if ((self->freq - freq_group) > 12) {
+                // quarterly frequency with year determined by ending period
+                self->value = year*4 + quarter;
+            } else {
+                /* quarterly frequency with year determined by ending period
+                   or has December year end*/
+                self->value = (year-1)*4 + quarter;
+            }
         } else if (freq_group == FR_ANN) {
             self->value = year;
         }
@@ -1890,8 +1967,13 @@
     char *orig_fmt_str, *fmt_str;
     char *result;
 
-    char extra_fmts[1][2][10] = {{"%q", "^`XZ`^"}};
-    int extra_fmts_found[1] = {0};
+    int num_extra_fmts = 3;
+
+    char extra_fmts[3][2][10] = {{"%q", "^`AB`^"},
+                                 {"%f", "^`CD`^"},
+                                 {"%F", "^`EF`^"}};
+
+    int extra_fmts_found[3] = {0,0,0};
     int extra_fmts_found_one = 0;
     struct tm c_date;
     struct date_info tempDate;
@@ -1931,7 +2013,7 @@
     fmt_str = orig_fmt_str;
 
     // replace any special format characters with their place holder
-    for(i=0; i < 1; i++) {
+    for(i=0; i < num_extra_fmts; i++) {
         char *special_loc;
         if ((special_loc = strstr(fmt_str,extra_fmts[i][0])) != NULL) {
             char *tmp_str = fmt_str;
@@ -1952,18 +2034,50 @@
     if (extra_fmts_found_one) { free(fmt_str); }
 
     // replace any place holders with the appropriate value
-    for(i=0; i < 1; i++) {
+    for(i=0; i < num_extra_fmts; i++) {
         if (extra_fmts_found[i]) {
             char *tmp_str = result;
             char *extra_str;
 
-            if(strcmp(extra_fmts[i][0], "%q") == 0) {
-                if ((extra_str = malloc(2 * sizeof(char))) == NULL) {
-                    free(tmp_str);
-                    return PyErr_NoMemory();
+            if (strcmp(extra_fmts[i][0], "%q") == 0 ||
+                strcmp(extra_fmts[i][0], "%f") == 0 ||
+                strcmp(extra_fmts[i][0], "%F") == 0) {
+
+                struct asfreq_info af_info;
+                int qtr_freq, year, quarter, year_len;
+
+                if (get_freq_group(self->freq) == FR_QTR) {
+                    qtr_freq = self->freq;
+                } else { qtr_freq = FR_QTR; }
+                get_asfreq_info(FR_DAY, qtr_freq, &af_info);
+
+                if(DtoQ_yq(absdate, &af_info, &year, &quarter) == INT_ERR_CODE)
+                { return NULL; }
+
+                if(strcmp(extra_fmts[i][0], "%q") == 0) {
+                    if ((extra_str = malloc(2 * sizeof(char))) == NULL) {
+                        free(tmp_str);
+                        return PyErr_NoMemory();
+                    }
+                    sprintf(extra_str, "%i", quarter);
+                } else {
+                    if ((qtr_freq % 1000) > 12) { year -= 1; }
+
+                    if (strcmp(extra_fmts[i][0], "%f") == 0) {
+                        year_len = 2;
+                        year = year % 100;
+                    } else { year_len = 4; }
+
+                    if ((extra_str = malloc((year_len+1) * sizeof(char))) == NULL) {
+                        free(tmp_str);
+                        return PyErr_NoMemory();
+                    }
+
+                    if (year_len == 2 && year < 10) {
+                        sprintf(extra_str, "0%i", year);
+                    } else { sprintf(extra_str, "%i", year); }
                 }
 
-                sprintf(extra_str, "%i", tempDate.quarter);
             } else {
                 PyErr_SetString(PyExc_RuntimeError,"Unrecogized fmt string");
                 return NULL;
@@ -1971,6 +2085,7 @@
 
             result = str_replace(result, extra_fmts[i][1], extra_str);
             free(tmp_str);
+            free(extra_str);
             if (result == NULL) { return NULL; }
         }
     }
@@ -1989,7 +2104,7 @@
     PyObject *string_arg, *retval;
 
     if (freq_group == FR_ANN) { string_arg = Py_BuildValue("(s)", "%Y"); }
-    else if (freq_group == FR_QTR) { string_arg = Py_BuildValue("(s)", "%YQ%q"); }
+    else if (freq_group == FR_QTR) { string_arg = Py_BuildValue("(s)", "%FQ%q"); }
     else if (freq_group == FR_MTH) { string_arg = Py_BuildValue("(s)", "%b-%Y"); }
     else if (freq_group == FR_DAY ||
              freq_group == FR_BUS ||
@@ -2222,11 +2337,45 @@
     return PyInt_FromLong(dinfo.year);
 }
 
+static int _DateObject_quarter_year(DateObject *self, int *year, int *quarter) {
+
+    PyObject *daily_obj;
+    long absdate;
+
+    struct asfreq_info af_info;
+    int qtr_freq;
+
+    daily_obj = DateObject_toordinal(self);
+    absdate = PyInt_AsLong(daily_obj);
+    Py_DECREF(daily_obj);
+
+    if (get_freq_group(self->freq) == FR_QTR) {
+        qtr_freq = self->freq;
+    } else { qtr_freq = FR_QTR; }
+    get_asfreq_info(FR_DAY, qtr_freq, &af_info);
+
+    if(DtoQ_yq(absdate, &af_info, year, quarter) == INT_ERR_CODE)
+    { return INT_ERR_CODE; }
+
+    if ((qtr_freq % 1000) > 12) { *year -= 1; }
+
+    return 0;
+}
+
 static PyObject *
+DateObject_qyear(DateObject *self, void *closure) {
+    int year, quarter;
+    if(_DateObject_quarter_year(self,
+            &year, &quarter) == INT_ERR_CODE) { return NULL; }
+    return PyInt_FromLong(year);
+}
+
+static PyObject *
 DateObject_quarter(DateObject *self, void *closure) {
-    struct date_info dinfo;
-    if(DateObject_set_date_info(self, &dinfo) == -1) return NULL;
-    return PyInt_FromLong(dinfo.quarter);
+    int year, quarter;
+    if(_DateObject_quarter_year(self,
+            &year, &quarter) == INT_ERR_CODE) { return NULL; }
+    return PyInt_FromLong(quarter);
 }
 
 static PyObject *
@@ -2305,6 +2454,12 @@
 static PyGetSetDef DateObject_getseters[] = {
     {"year", (getter)DateObject_year, (setter)DateObject_ReadOnlyErr,
             "Returns the year.", NULL},
+    {"qyear", (getter)DateObject_qyear, (setter)DateObject_ReadOnlyErr,
+            "For quarterly frequency dates, returns the year corresponding to the\n"
+            "year end (start) month. When using QTR or QTR-E based quarterly\n"
+            "frequencies, this is the fiscal year in a financial context.\n\n"
+            "For non-quarterly dates, this simply returns the year of the date.",
+            NULL},
     {"quarter", (getter)DateObject_quarter, (setter)DateObject_ReadOnlyErr,
             "Returns the quarter.", NULL},
     {"month", (getter)DateObject_month, (setter)DateObject_ReadOnlyErr,
@@ -2785,74 +2940,68 @@
     PyArrayObject *array;
     PyArrayObject *newArray;
     PyArrayIterObject *iterSource, *iterResult;
-    struct date_info convDate;
 
-    PyObject *val;
-    long dateNum, dInfo;
-    long absdate;
-    double abstime;
+    PyObject* (*getDateInfo)(DateObject*, void*) = NULL;
 
-    long (*toDaily)(long, char, struct asfreq_info*) = NULL;
-    int (*getDateInfo)(struct date_info*) = NULL;
-    struct asfreq_info af_info;
-
     if (!PyArg_ParseTuple(args, "Ois:getDateInfo(array, freq, info)", &array, &freq, &info)) return NULL;
     newArray = (PyArrayObject *)PyArray_Copy(array);
 
     iterSource = (PyArrayIterObject *)PyArray_IterNew((PyObject *)array);
     iterResult = (PyArrayIterObject *)PyArray_IterNew((PyObject *)newArray);
 
-    toDaily = get_asfreq_func(freq, FR_DAY, 0);
-    get_asfreq_info(freq, FR_DAY, &af_info);
 
     switch(*info)
     {
         case 'Y': //year
-            getDateInfo = &dInfo_year;
+            getDateInfo = &DateObject_year;
             break;
+        case 'F': //"fiscal" year
+            getDateInfo = &DateObject_qyear;
+            break;
         case 'Q': //quarter
-            getDateInfo = &dInfo_quarter;
+            getDateInfo = &DateObject_quarter;
             break;
         case 'M': //month
-            getDateInfo = &dInfo_month;
+            getDateInfo = &DateObject_month;
             break;
         case 'D': //day
-            getDateInfo = &dInfo_day;
+            getDateInfo = &DateObject_day;
             break;
         case 'R': //day of year
-            getDateInfo = &dInfo_day_of_year;
+            getDateInfo = &DateObject_day_of_year;
             break;
         case 'W': //day of week
-            getDateInfo = &dInfo_day_of_week;
+            getDateInfo = &DateObject_day_of_week;
             break;
         case 'I': //week of year
-            getDateInfo = &dInfo_week;
+            getDateInfo = &DateObject_week;
             break;
         case 'H': //hour
-            getDateInfo = &dInfo_hour;
+            getDateInfo = &DateObject_hour;
             break;
         case 'T': //minute
-            getDateInfo = &dInfo_minute;
+            getDateInfo = &DateObject_minute;
             break;
         case 'S': //second
-            getDateInfo = &dInfo_second;
+            getDateInfo = &DateObject_second;
             break;
         default:
             return NULL;
     }
 
     while (iterSource->index < iterSource->size) {
+        DateObject *curr_date;
+        PyObject *val, *dInfo;
 
         val = PyArray_GETITEM(array, iterSource->dataptr);
-        dateNum = PyInt_AsLong(val);
-        Py_DECREF(val);
-        CHECK_ASFREQ(absdate = toDaily(dateNum, 'B', &af_info));
-        abstime = getAbsTime(freq, absdate, dateNum);
+        curr_date = DateObject_FromFreqAndValue(freq, PyInt_AsLong(val));
+        dInfo = getDateInfo(curr_date, NULL);
 
-        if(dInfoCalc_SetFromAbsDateTime(&convDate, absdate, abstime, GREGORIAN_CALENDAR)) return NULL;
-        dInfo = getDateInfo(&convDate);
+        PyArray_SETITEM(newArray, iterResult->dataptr, dInfo);
 
-        PyArray_SETITEM(newArray, iterResult->dataptr, PyInt_FromLong(dInfo));
+        Py_DECREF(val);
+        Py_DECREF(curr_date);
+        Py_DECREF(dInfo);
 
         PyArray_ITER_NEXT(iterSource);
         PyArray_ITER_NEXT(iterResult);




More information about the Scipy-svn mailing list