[Scipy-svn] r2370 - in trunk/Lib/sandbox: . timeseries
scipy-svn at scipy.org
scipy-svn at scipy.org
Fri Dec 8 11:06:10 EST 2006
Author: mattknox_ca
Date: 2006-12-08 10:05:35 -0600 (Fri, 08 Dec 2006)
New Revision: 2370
Added:
trunk/Lib/sandbox/timeseries/
trunk/Lib/sandbox/timeseries/README
trunk/Lib/sandbox/timeseries/__init__.py
trunk/Lib/sandbox/timeseries/__init__.pyc
trunk/Lib/sandbox/timeseries/corelib.py
trunk/Lib/sandbox/timeseries/corelib.pyc
trunk/Lib/sandbox/timeseries/cseries.pyd
trunk/Lib/sandbox/timeseries/cseriesmodule.c
trunk/Lib/sandbox/timeseries/shiftingarray.py
trunk/Lib/sandbox/timeseries/shiftingarray.pyc
trunk/Lib/sandbox/timeseries/timeseries.py
trunk/Lib/sandbox/timeseries/timeseries.pyc
trunk/Lib/sandbox/timeseries/tsdate.py
trunk/Lib/sandbox/timeseries/tsdate.pyc
Log:
uploaded timeseries module to sandbox
Added: trunk/Lib/sandbox/timeseries/README
===================================================================
--- trunk/Lib/sandbox/timeseries/README 2006-12-08 05:13:33 UTC (rev 2369)
+++ trunk/Lib/sandbox/timeseries/README 2006-12-08 16:05:35 UTC (rev 2370)
@@ -0,0 +1,22 @@
+Requirements and warnings:
+
+1. version 2.0.x of the mx DateTime module MUST be installed. Only "tested" with 2.0.3
+2. Only tested with numpy 1.0.1
+3. Only tested with Python 2.4.x
+4. Only tested on Windows Platform
+5. the included cseries.pyd file was compiled for 32-bit windows, so if you are trying
+ this on another platform, the first thing you need to do is recompile it
+
+
+Instructions:
+
+1. read through the included example.py script in the examples subfolder. This illustrates
+ the basic functionality of the module. I recommend placing print statements after each
+ variable assignment, one at a time, to see the result of each item in the examples.
+
+ Documentation is very limited, so the examples really are the best starting point.
+
+2. Before you get too crazy and start modifying the examples and writing your own scripts,
+ please read todo.txt in the doc subdirectory for an outline of limitations in the current
+ module.
+
Added: trunk/Lib/sandbox/timeseries/__init__.py
===================================================================
--- trunk/Lib/sandbox/timeseries/__init__.py 2006-12-08 05:13:33 UTC (rev 2369)
+++ trunk/Lib/sandbox/timeseries/__init__.py 2006-12-08 16:05:35 UTC (rev 2370)
@@ -0,0 +1,5 @@
+from timeseries import *
+from tsdate import *
+from corelib import *
+from numpy import ma
+masked = ma.masked
\ No newline at end of file
Added: trunk/Lib/sandbox/timeseries/__init__.pyc
===================================================================
(Binary files differ)
Property changes on: trunk/Lib/sandbox/timeseries/__init__.pyc
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/Lib/sandbox/timeseries/corelib.py
===================================================================
--- trunk/Lib/sandbox/timeseries/corelib.py 2006-12-08 05:13:33 UTC (rev 2369)
+++ trunk/Lib/sandbox/timeseries/corelib.py 2006-12-08 16:05:35 UTC (rev 2370)
@@ -0,0 +1,79 @@
+import numpy
+
+#converts possible strings for frequency into acceptable values
+def fmtFreq (freqStr):
+ if freqStr is None:
+ return None
+ elif freqStr.upper() in ("A","ANNUAL","B","BUSINESS","D","DAILY","M","MONTHLY","Q","QUARTERLY","S","SECONDLY"):
+ return freqStr[0].upper()
+ else:
+ raise ValueError("Invalid frequency: "+str(freqStr))
+
+
+#converts possible strings for observed into acceptable values
+def fmtObserv(obStr):
+
+ obsVals = ( "UNDEFINED",
+ "BEGINNING",
+ "END",
+ "AVERAGED",
+ "SUMMED",
+ "ANNUALIZED",
+ "FORMULA",
+ "HIGH",
+ "LOW")
+
+ if obStr is None:
+ return None
+ elif obStr.upper() in obsVals:
+ return obStr.upper()
+ elif obStr.upper() in ("UNDEFINED", "BEGIN", "END", "AVERAGE", "SUM", "ANNUAL" , "FORMULA", "HIGH", "LOW"):
+ obStr = obStr.upper()
+ for x in obsVals:
+ if obStr[:2] == x[:2]:
+ return x
+ else:
+ raise ValueError("Invalid value for observed attribute: "+str(obStr))
+
+def freqToType(freq):
+ return freqTypeMapping[fmtFreq(freq)]
+
+
+# fake data type for date variables
+class DateSpec:
+ def __init__(self, freq):
+ self.freq = fmtFreq(freq)
+
+ def __hash__(self): return hash(self.freq)
+
+ def __eq__(self, other):
+ if hasattr(other, "freq"): return self.freq == other.freq
+ else: return False
+
+ def __str__(self): return "Date(" + str(self.freq) + ")"
+
+
+
+# define custom numpy types.
+# Note: A more robust approach would register these as actual valid numpy types
+# this is just a hack for now
+numpy.dateS = DateSpec("Secondly")
+numpy.dateD = DateSpec("Daily")
+numpy.dateB = DateSpec("Business")
+numpy.dateM = DateSpec("Monthly")
+numpy.dateQ = DateSpec("Quarterly")
+numpy.dateA = DateSpec("Annual")
+
+freqTypeMapping = {
+ 'S':numpy.dateS,
+ 'D':numpy.dateD,
+ 'B':numpy.dateB,
+ 'M':numpy.dateM,
+ 'Q':numpy.dateQ,
+ 'A':numpy.dateA
+}
+
+def isDateType(dtype):
+ if len([x for x in (numpy.dateS,numpy.dateD,numpy.dateB,numpy.dateM,numpy.dateQ,numpy.dateA) if x == dtype]) > 0: return True
+ else: return False
+
Added: trunk/Lib/sandbox/timeseries/corelib.pyc
===================================================================
(Binary files differ)
Property changes on: trunk/Lib/sandbox/timeseries/corelib.pyc
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/Lib/sandbox/timeseries/cseries.pyd
===================================================================
(Binary files differ)
Property changes on: trunk/Lib/sandbox/timeseries/cseries.pyd
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/Lib/sandbox/timeseries/cseriesmodule.c
===================================================================
--- trunk/Lib/sandbox/timeseries/cseriesmodule.c 2006-12-08 05:13:33 UTC (rev 2369)
+++ trunk/Lib/sandbox/timeseries/cseriesmodule.c 2006-12-08 16:05:35 UTC (rev 2370)
@@ -0,0 +1,538 @@
+#include <Python.h>
+//#include <datetime.h>
+#include <structmember.h>
+#include <stdio.h>
+#include <string.h>
+#include "mxDateTime.h"
+#include "arrayobject.h"
+
+static char cseries_doc[] = "Speed sensitive time series operations";
+
+///////////////////////////////////////////////////////////////////////
+
+
+static int
+freqVal(char freq)
+{
+ switch(freq)
+ {
+ case 'A':
+ //annual
+ return 1;
+ case 'Q':
+ //quarterly
+ return 2;
+ case 'M':
+ //monthly
+ return 3;
+ case 'B':
+ //business
+ return 4;
+ case 'D':
+ //daily
+ return 5;
+ default:
+ return 0;
+ }
+}
+
+
+//fromDate is periods since Dec 31, 1849
+static long
+convert(long fromDate, char fromFreq, char toFreq, int notStartInd, int atEnd)
+{
+ long absdate, origin, secondorigin, secsInDay;
+ long converted;
+ int rem;
+ int y,m,d,s;
+
+ mxDateTimeObject *theDate;
+ mxDateTimeObject *convDate;
+
+ origin = 675333;
+ secondorigin = 722814;
+ secsInDay = 86400;
+
+ //convert fromDate to days since Dec 31, 1849 (Jan 1, 1850 would have absdate of 1)
+ switch(fromFreq)
+ {
+ case 'D':
+ absdate = fromDate;
+ break;
+ case 'B':
+ absdate = (fromDate/5)*7 + fromDate%5;
+ break;
+ case 'M':
+ y = fromDate/12 + 1;
+ m = fromDate%12;
+ if (atEnd) m++;
+ if (m == 0)
+ {
+ m = 12;
+ y--;
+ }
+ d=1;
+ break;
+ case 'Q':
+ y = fromDate/4 + 1;
+ m = (fromDate%4) * 3;
+ if (!atEnd) m -= 2; //change to first month of quarter
+ else m += 1;
+ if (m < 1)
+ {
+ m += 12;
+ y--;
+ }
+ else if (m == 12)
+ {
+ m = 1;
+ y++;
+ }
+ d=1;
+ break;
+ case 'A':
+ y = fromDate-1;
+ if (atEnd == 1) y++;
+ m = 1;
+ d = 1;
+ break;
+ default:
+ return -1;
+ }
+
+ if (freqVal(fromFreq) < 4)
+ {
+ //switch to years from 0 for mxDateTime
+ y+= 1849;
+
+ theDate = (mxDateTimeObject *)mxDateTime.DateTime_FromDateAndTime(y,m,d,0,0,0);
+ absdate = (long)(theDate->absdate);
+ if (atEnd == 1) absdate--;
+ }
+ else
+ {
+ //days from 0 for mxDateTime
+ absdate += origin;
+ }
+
+ if (atEnd) s = secsInDay-1;
+ else s = 0;
+
+ convDate = (mxDateTimeObject *)mxDateTime.DateTime_FromAbsDateAndTime(absdate,s);
+
+ //switch back to days and years since 1849 for pyTSA Date
+ absdate -= origin;
+ y = convDate->year - 1849;
+ m = convDate->month;
+
+ //convert convDate to appropriate # of periods according to toFreq
+ switch(toFreq)
+ {
+ case 'D':
+ converted = absdate;
+ break;
+ case 'B':
+ rem = absdate%7;
+ if (rem > 4) //is weekend day
+ {
+ if (notStartInd == 1 && freqVal(fromFreq) > 4)
+ {
+ return -1;
+ }
+ else
+ {
+ d = convDate->day;
+ d -= rem - 4; //change to friday before weekend
+ if (d < 1) d += 3; //if friday was prev. month, change to monday instead
+ absdate = absdate - convDate->day + d;
+ converted = (long)((absdate / 7 * 5.0) + absdate%7);
+ }
+ }
+ else
+ {
+ converted = (long)((absdate / 7 * 5.0) + rem);
+ }
+ break;
+ case 'M':
+ converted = (long)((y-1)*12 + m);
+ break;
+ case 'Q':
+ converted = (long)((y-1)*4 + ((m-1)/3) + 1);
+ break;
+ case 'A':
+ converted = (long)(y+1);
+ break;
+ default:
+ return -1;
+ }
+
+ return converted;
+}
+
+
+static long
+expand(long oldSize, char fromFr, char toFr)
+{
+ long newSize;
+ int fromFreq, toFreq;
+
+ if (fromFr == toFr) return oldSize;
+
+ fromFreq = freqVal(fromFr);
+ toFreq = freqVal(toFr);
+ if (fromFreq*toFreq == 0) return oldSize; //invalid frequency
+
+ newSize = oldSize;
+
+ while (toFreq > fromFreq)
+ {
+ if (fromFreq == 1) //Annual
+ {
+ newSize *= 4; //quarters in year
+ fromFreq++;
+ }
+ else if (fromFreq == 2) //Quarterly
+ {
+ newSize *= 3; //months in quarter
+ fromFreq++;
+ }
+ else if (fromFreq == 3) //Monthly
+ {
+ newSize *= 31; //max days in month
+ fromFreq++;
+ }
+ else if (fromFreq == 4) //Business
+ {
+ newSize *= 2; //max d days for each b days
+ fromFreq++;
+ }
+ }
+
+
+ return newSize;
+}
+
+
+///////////////////////////////////////////////////////////////////////
+/*
+OBSERVED
+
+from lower freq to higher freq
+----------------------
+
+summed -- all values in period set as lower freq's value / # of values
+
+rest -- all values in period set as lower freq's value
+
+from higher freq to lower freq
+----------------------
+begin - lower freq's value set as first value in period
+end - lower freq's value set as end value in period
+summed - lower freq's value set as sum of all values in period
+averaged - lower freq's value set as average of all values in period
+high - lower freq's value set as largest value in period
+low - lower freq's value set as smallest value in period
+
+*/
+///////////////////////////////////////////////////////////////////////
+
+static void
+adjValForObsSet(PyArrayObject *theArray, char obs, PyObject **newVal, PyObject **newValMask, PyObject *val, PyObject *valMask, long curPerLen)
+{
+ double dblVal;
+ long lngValMask, lngAllMasked;
+
+ lngValMask = PyInt_AsLong(valMask);
+ lngAllMasked = PyInt_AsLong(*newValMask);
+
+ if (!lngValMask) {
+
+ // if any value is not masked, then we shall not mask the aggregated result
+ *newValMask = valMask;
+
+ if (obs == 'B')
+ {
+ if (lngAllMasked) {
+ *newVal = val;
+ }
+ }
+ else if ( PyArray_ISFLOAT(theArray) && (obs=='S' || obs=='A') )
+ {
+
+ if (obs == 'S')
+ {
+ //observed is summed
+
+ dblVal = PyFloat_AsDouble(*newVal);
+ dblVal += PyFloat_AsDouble(val);
+ *newVal = PyFloat_FromDouble(dblVal);
+ }
+ else
+ {
+ //observed is averaged
+
+ dblVal = PyFloat_AsDouble(*newVal);
+ dblVal *= (curPerLen-1);
+ dblVal += PyFloat_AsDouble(val);
+ dblVal /= curPerLen;
+ *newVal = PyFloat_FromDouble(dblVal);
+ }
+
+ }
+ else if ( PyArray_ISNUMBER(theArray) && (obs=='H' || obs=='L') )
+ {
+
+ if (obs == 'H')
+ {
+ //observed is high
+
+ if (PyFloat_AsDouble(val) > PyFloat_AsDouble(*newVal)) *newVal = val;
+ }
+ else if (obs == 'L')
+ {
+ //observed is low
+
+ if (PyFloat_AsDouble(val) < PyFloat_AsDouble(*newVal)) *newVal = val;
+ }
+
+ }
+ else
+ {
+ //observed is not beginning and
+ //val is string or (val is date and observed is summed/averaged)
+ //or observed is end or not supported
+
+ *newVal = val;
+ }
+ }
+
+}
+
+
+static //PyArrayObject *
+setArrayItem(PyArrayObject **theArray, long index, PyObject *newVal)
+{
+ char *setptr;
+
+ if (index >= 0)
+ {
+ //set value in array
+ setptr = (*theArray)->data + (index) * (*theArray)->strides[0];
+ PyArray_SETITEM(*theArray,setptr,newVal);
+ }
+
+ //return theArray;
+}
+
+
+static char cseries_reindex_doc[] = "";
+static PyObject *
+cseries_reindex(PyObject *self, PyObject *args)
+{
+ PyArrayObject *array;
+ PyArrayObject *tempArray;
+ PyArrayObject *newArray;
+
+ PyArrayObject *mask;
+ PyArrayObject *tempMask;
+ PyArrayObject *newMask;
+
+ PyObject *returnVal = NULL;
+
+ int notStartInd, atEnd;
+ long startIndex, newStart;
+ long i, curPerInd, nextPerInd, prevIndex, curIndex;
+ long dim;
+ long curPerLen;
+ long lngValMask;
+ char *fromFreq, *toFreq, *observed;
+
+ char *getptr;
+ PyObject *val, *newVal;
+
+ char *getptrMask;
+ PyObject *valMask, *newValMask;
+
+ int toFrVal, fromFrVal;
+
+ returnVal = PyDict_New();
+
+ if (!PyArg_ParseTuple(args, "OssslO:reindex(array, fromfreq, tofreq, observed, startIndex,mask)", &tempArray, &fromFreq, &toFreq, &observed, &startIndex, &tempMask)) return NULL;
+
+ if (toFreq[0] == fromFreq[0])
+ {
+
+ PyDict_SetItemString(returnVal, "values", (PyObject*)tempArray);
+ PyDict_SetItemString(returnVal, "mask", (PyObject*)tempMask);
+
+ return returnVal;
+ }
+
+ array = PyArray_GETCONTIGUOUS(tempArray);
+ mask = PyArray_GETCONTIGUOUS(tempMask);
+
+ //expand size to fit new values if needed
+ dim = expand(array->dimensions[0], fromFreq[0], toFreq[0]);
+
+ //initialize new array
+ newArray = (PyArrayObject*)PyArray_SimpleNew(array->nd, &dim, array->descr->type_num);
+ newMask = (PyArrayObject*)PyArray_SimpleNew(mask->nd, &dim, mask->descr->type_num);
+
+ for (i = 0; i < dim; i++)
+ {
+ setArrayItem(&newArray, i, PyInt_FromLong(1));
+ setArrayItem(&newMask, i, PyInt_FromLong(1));
+ }
+
+ //convert start index to new frequency
+ notStartInd = 0;
+ atEnd = 0;
+ newStart = convert(startIndex, fromFreq[0], toFreq[0], notStartInd, atEnd);
+
+ //initialize prevIndex
+ prevIndex = newStart - 1;
+
+ notStartInd = 1;
+ atEnd = 0;
+
+ //set values in the new array
+ for (i = 0; i < array->dimensions[0]; i++)
+ {
+ //find index for start of current period in new frequency
+ curPerInd = convert(startIndex + i, fromFreq[0], toFreq[0], notStartInd, atEnd);
+
+ //get frequency numeric mapping
+ fromFrVal = freqVal(fromFreq[0]);
+ toFrVal = freqVal(toFreq[0]);
+
+ //get value from old array
+ getptr = array->data + i*array->strides[0];
+ val = PyArray_GETITEM(array,getptr);
+
+ //get the mask corresponding to the old value
+ getptrMask = mask->data + i*mask->strides[0];
+ valMask = PyArray_GETITEM(mask,getptrMask);
+
+ if (fromFrVal < toFrVal)
+ {
+ //from lower freq to higher freq
+
+ newVal = val;
+ newValMask = valMask;
+
+ //find index for start of next period in new frequency
+ nextPerInd = convert(startIndex + i + 1, fromFreq[0], toFreq[0], notStartInd, atEnd);
+
+ //adjust for observed setting
+ if (observed[0] == 'S' && PyArray_ISFLOAT(array) && !( (fromFrVal == 4 && toFrVal == 5) || (fromFrVal == 5 && toFrVal == 4) ) )
+ {
+ //summed
+
+ //all values in period set as old array's value / # of values
+ newVal = PyFloat_FromDouble( PyFloat_AsDouble(val) / (nextPerInd - curPerInd) );
+ }
+
+ //set each value in period
+ for (curIndex = curPerInd; curIndex < nextPerInd; curIndex++)
+ {
+ setArrayItem(&newArray, curIndex-newStart, newVal);
+ setArrayItem(&newMask, curIndex-newStart, newValMask);
+ }
+ }
+ else
+ {
+
+ lngValMask = PyInt_AsLong(valMask);
+
+ //from higher freq to lower freq
+
+ if (curPerInd != prevIndex)
+ {
+ //starting new period in old array
+
+
+ //set value in the new array
+ setArrayItem(&newArray, prevIndex-newStart, newVal);
+ setArrayItem(&newMask, prevIndex-newStart, newValMask);
+
+ //reset period length
+ curPerLen = 0;
+
+
+
+ if (!lngValMask) {
+ curPerLen++;
+ }
+
+
+
+ //store current index and value
+ prevIndex = curPerInd;
+ newVal = val;
+ newValMask = valMask;
+
+ }
+ else
+ {
+ //still in same period
+
+
+
+ if (!lngValMask) {
+ curPerLen++;
+ }
+
+ //adjust new value according to observed setting
+ adjValForObsSet(array, observed[0], &newVal, &newValMask, val, valMask, curPerLen);
+ }
+
+ }
+
+ }
+
+ //set value of last item in the new array
+ setArrayItem(&newArray, curPerInd-newStart, newVal);
+ setArrayItem(&newMask, curPerInd-newStart, newValMask);
+
+ PyDict_SetItemString(returnVal, "values", (PyObject*)newArray);
+ PyDict_SetItemString(returnVal, "mask", (PyObject*)newMask);
+
+ return returnVal;
+
+}
+
+
+static char cseries_convert_doc[] = "";
+static PyObject *
+cseries_convert(PyObject *self, PyObject *args)
+{
+ long fromDate;
+ char* fromFreq;
+ char* toFreq;
+ int notStartInd, atEnd;
+
+ if (!PyArg_ParseTuple(args, "lss:convert(fromDate, fromfreq, tofreq)", &fromDate, &fromFreq, &toFreq)) return NULL;
+
+ //always want start of period (only matters when converting from lower freq to higher freq ie. m -> d)
+ atEnd = 0;
+ notStartInd = 0;
+
+ return PyInt_FromLong(convert(fromDate, fromFreq[0], toFreq[0], notStartInd, atEnd));
+}
+
+
+///////////////////////////////////////////////////////////////////////
+
+static PyMethodDef cseries_methods[] = {
+ {"reindex", cseries_reindex, METH_VARARGS, cseries_reindex_doc},
+ {"convert", cseries_convert, METH_VARARGS, cseries_convert_doc},
+ {NULL, NULL}
+};
+
+PyMODINIT_FUNC
+initcseries(void)
+{
+ Py_InitModule3("cseries", cseries_methods, cseries_doc);
+ mxDateTime_ImportModuleAndAPI();
+ import_array();
+}
\ No newline at end of file
Added: trunk/Lib/sandbox/timeseries/shiftingarray.py
===================================================================
--- trunk/Lib/sandbox/timeseries/shiftingarray.py 2006-12-08 05:13:33 UTC (rev 2369)
+++ trunk/Lib/sandbox/timeseries/shiftingarray.py 2006-12-08 16:05:35 UTC (rev 2370)
@@ -0,0 +1,302 @@
+import numpy, types , corelib
+import copy
+from numpy import ma
+
+class ShiftingArray(object):
+ def __init__(self, values, dtype=None, startIndex=None, mask=ma.nomask):
+
+ # hack to convert our fake date data types to real data types
+ if corelib.isDateType(dtype):
+ self.dtype = numpy.int_
+ else:
+ self.dtype = dtype
+
+ if self.dtype is None:
+ self.dtype = values.dtype
+
+ # need to use the empty function instead of passing an empty list
+ # because that won't work when type=numpy.object_
+ if len(values) == 0 and dtype is numpy.object_:
+ tempData = ma.array(numpy.empty((0,), self.dtype))
+ else:
+ tempData = ma.array(values, self.dtype)
+
+ newSize = tempData.size*2
+
+ firstIndex = newSize//4
+ lastIndex = firstIndex + tempData.size - 1
+ if startIndex is None:
+ self.indexZeroRepresents = None
+ else:
+ self.indexZeroRepresents = int(startIndex)-firstIndex
+
+ if mask is not ma.nomask:
+ tempMask = ma.make_mask(mask)
+ tempData[tempMask] = ma.masked
+
+ self.data = ma.array(numpy.empty(newSize,self.dtype))
+
+ if firstIndex > 0:
+ self.data[0:firstIndex] = ma.masked
+ if self.data.size > lastIndex+1: self.data[lastIndex+1:self.data.size] = ma.masked
+
+ self.data[firstIndex:lastIndex+1] = tempData[:]
+
+
+ def shift(self, n):
+ self.indexZeroRepresents += n
+
+
+ #DATA ACCESS
+
+ def __setitem__(self, index, value):
+ self.__expandToFit(self.__minIndex(index),self.__maxIndex(index))
+ convIndex = self.__convIndex(index)
+ self.data[convIndex] = value
+
+
+ def __getitem__(self, index):
+ self.__expandToFit(self.__minIndex(index),self.__maxIndex(index))
+ convIndex = self.__convIndex(index)
+ return self.data[convIndex]
+
+ def _shift(self, startIndex, endIndex):
+ self.__expandToFit(startIndex, endIndex)
+ return self.data[startIndex-self.indexZeroRepresents:endIndex-self.indexZeroRepresents+1]
+
+
+ #PRIVATE FUNCTIONS
+
+ def __convIndex(self,index):
+
+ if self.indexZeroRepresents is not None:
+ if isinstance(index,ShiftingArray):
+
+ if index.indexZeroRepresents > self.indexZeroRepresents:
+ #expand index to the left
+ originalSize = index.data.size
+ shiftAmt = index.indexZeroRepresents - self.indexZeroRepresents
+ newSize = originalSize + shiftAmt
+ temp = ma.array(numpy.empty(newSize, index.data.dtype))
+ temp[newSize-originalSize:] = index.data
+ temp[0:shiftAmt] = False
+ temp = temp.filled(False)
+ else:
+ #chop off first portion of data
+ temp = index.data[self.indexZeroRepresents - index.indexZeroRepresents:].filled(False)
+
+ # chop off extra values on right hand side
+ if temp.size > self.data.size: return temp[:self.data.size]
+ else: return temp
+
+ elif type(index) == types.SliceType:
+ if index.start is None: tempStart = None
+ else: tempStart = index.start - self.indexZeroRepresents
+ if index.stop is None: tempStop = None
+ else: tempStop = index.stop - self.indexZeroRepresents
+ tempStep = index.step
+
+ return slice(tempStart,tempStop,tempStep)
+ else:
+ return index - self.indexZeroRepresents
+
+ else:
+ return index
+
+ def __maxIndex(self,index):
+ if type(index) == types.IntType: return index
+ if type(index) == types.SliceType: return index.stop
+ elif isinstance(index,ShiftingArray): return index.lastValue()
+ elif hasattr(index,'__len__'): return max(index)
+ else: return int(index)
+
+ def __minIndex(self,index):
+ if type(index) == types.IntType: return index
+ if type(index) == types.SliceType: return index.start
+ elif isinstance(index,ShiftingArray): return index.firstValue()
+ elif hasattr(index,'__len__'): return min(index)
+ else: return int(index)
+
+ def __expandToFit(self, minRange, maxRange=None):
+
+ if self.indexZeroRepresents is None:
+ self.indexZeroRepresents = minRange
+
+ if maxRange is None:
+ maxRange = minRange
+ if maxRange < minRange:
+ raise ValueError("invalid range: " + str(minRange) + " to " + str(maxRange))
+
+ minRange -= self.indexZeroRepresents
+ maxRange -= self.indexZeroRepresents
+
+ if maxRange > self.data.size-1: #expand to the right
+ originalSize = self.data.size
+ newSize = originalSize
+ while maxRange > newSize-1:
+ newSize = expandAmt(newSize)
+
+ self.data = self.data.resize(numpy.shape(numpy.empty(newSize)))
+ self.data[originalSize:] = ma.masked
+
+
+ if minRange < 0: #expand to the left
+ originalSize = self.data.size
+ newSize = originalSize
+ shiftAmt = int(0)
+ while minRange + shiftAmt < 0:
+ newSize = expandAmt(newSize)
+ shiftAmt = int(newSize - originalSize)
+
+ temp = ma.array(numpy.empty(newSize, self.data.dtype))
+ temp[newSize-originalSize:] = self.data
+ self.data = temp
+ self.data[0:shiftAmt] = ma.masked
+
+ self.indexZeroRepresents -= shiftAmt
+
+
+
+ #MATH FUNCTIONS
+
+ def __add__(self, other,fill_value=ma.masked): return doFunc(self,other, ma.add,fill_value=fill_value)
+ def __radd__(self, other): return self+other
+ def __sub__(self, other,fill_value=ma.masked): return doFunc(self,other, ma.subtract,fill_value=fill_value)
+ def __rsub__(self, other): return doFunc((self*-1),other, ma.add)
+ def __mul__(self, other,fill_value=ma.masked): return doFunc(self,other, ma.multiply,fill_value=fill_value)
+ def __rmul__(self, other): return self*other
+ def __div__(self, other,fill_value=ma.masked): return doFunc(self,other, ma.divide,fill_value=fill_value)
+ def __rdiv__(self, other): return doFunc(pow(self,-1),other, ma.multiply)
+ def __pow__(self, other,fill_value=ma.masked): return doFunc(self,other, ma.power,fill_value=fill_value)
+
+ def __eq__(self, other): return doFunc(self,other, ma.equal)
+ def __le__(self, other): return doFunc(self,other, ma.less_equal)
+ def __lt__(self, other): return doFunc(self,other, ma.less)
+ def __ge__(self, other): return doFunc(self,other, ma.greater_equal)
+ def __gt__(self, other): return doFunc(self,other, ma.greater)
+
+ def max(self,other): return doFunc(self,other, ma.maximum)
+ def min(self,other): return doFunc(self,other, ma.minimum)
+
+ #INFO FUNCTIONS
+
+ def __len__(self):
+ fv = self.firstValue()
+ if fv is not None:
+ return self.lastValue()-fv+1
+ else:
+ return 0
+
+ def firstValue(self):
+ firstIndex = first_unmasked(self.data)
+ if self.indexZeroRepresents is None or firstIndex is None:
+ return None
+ else:
+ return firstIndex+self.indexZeroRepresents
+
+
+ def lastValue(self):
+ lastIndex = last_unmasked(self.data)
+ if self.indexZeroRepresents is None or lastIndex is None:
+ return None
+ else:
+ return lastIndex+self.indexZeroRepresents
+
+
+ #DISPLAY FUNCTIONS
+
+ def __str__(self):
+ retVal = ""
+ if self.firstValue() is not None:
+ for i in range(first_unmasked(self.data), last_unmasked(self.data)+1):
+ index = str(i+self.indexZeroRepresents)
+ index = index + (" " * (6-len(index)))
+ retVal += index + "---> " + str(self.data[i]) + "\n"
+ return retVal
+ else:
+ return "<no data>"
+
+ def show(self, showLists=True):
+ print "indexZeroRepresents = ", self.indexZeroRepresents
+ print self.data
+
+
+
+#apply func to ser1 and ser2, replacing masked values with fill_value
+def doFunc(ser1, ser2, func,fill_value=ma.masked):
+ if not isinstance(ser2, ShiftingArray):
+ if ser1.indexZeroRepresents is None:
+ return ShiftingArray([],ser1.data.dtype)
+ else:
+ ser2 = ShiftingArray([ser2]*len(ser1),ser1.data.dtype, ser1.firstValue())
+
+ sFV, sLV = ser1.firstValue(), ser1.lastValue()
+ oFV, oLV = ser2.firstValue(), ser2.lastValue()
+
+ if ser1.indexZeroRepresents is not None and ser2.indexZeroRepresents is not None:
+ if fill_value is not ma.masked:
+ minVal = min(sFV, oFV)
+ maxVal = max(sLV, oLV)
+ else:
+ minVal = max(sFV, oFV)
+ maxVal = min(sLV, oLV)
+ elif ser1.indexZeroRepresents is None and ser2.indexZeroRepresents is None:
+ return ShiftingArray([],ser1.data.dtype)
+ elif ser1.indexZeroRepresents is None:
+ minVal = oFV
+ maxVal = oLV
+ else: #ser2.indexZeroRepresents is None:
+ minVal = sFV
+ maxVal = sLV
+
+ if maxVal < minVal:
+ return ShiftingArray([],ser1.data.dtype, startIndex=minVal)
+
+ data1 = ser1._shift(minVal, maxVal)
+ data2 = ser2._shift(minVal, maxVal)
+
+ if fill_value is ma.masked:
+ mask = data1.mask | data2.mask
+ else:
+ mask = data1.mask & data2.mask
+
+ data1 = data1.filled(fill_value)
+ data2 = data2.filled(fill_value)
+
+ data = func(data1,data2)
+
+ return ShiftingArray(data,data.dtype,minVal, mask)
+
+
+def doFunc_oneseries(ser,func):
+
+ sFV = ser.firstValue()
+
+ if sFV is None:
+ return ser
+ else:
+ result = func(ser.data)
+ return ShiftingArray(result,result.dtype,sFV,result.mask)
+
+
+#MISC GLOBAL FUNCTIONS
+
+def expandAmt(size):
+ EXPAND_MULT = 1.2
+ EXPAND_ADD = 5
+ return round(size*EXPAND_MULT) + EXPAND_ADD
+
+
+def first_unmasked(m):
+ idx = numpy.where(m.mask == False)
+ if len(idx) != 0 and len(idx[0]) != 0:
+ return idx[0][0]
+ else:
+ return None
+
+def last_unmasked(m):
+ idx = numpy.where(m.mask == False)
+ if len(idx) != 0 and len(idx[0]) != 0:
+ return idx[0][-1]
+ else:
+ return None
\ No newline at end of file
Added: trunk/Lib/sandbox/timeseries/shiftingarray.pyc
===================================================================
(Binary files differ)
Property changes on: trunk/Lib/sandbox/timeseries/shiftingarray.pyc
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/Lib/sandbox/timeseries/timeseries.py
===================================================================
--- trunk/Lib/sandbox/timeseries/timeseries.py 2006-12-08 05:13:33 UTC (rev 2369)
+++ trunk/Lib/sandbox/timeseries/timeseries.py 2006-12-08 16:05:35 UTC (rev 2370)
@@ -0,0 +1,232 @@
+import numpy
+from numpy import ma
+import types
+
+import corelib
+import shiftingarray as sa
+from shiftingarray import doFunc, doFunc_oneseries
+import cseries
+import tsdate
+import copy
+
+class TimeSeries(sa.ShiftingArray):
+ def __init__(self,values=[], dtype=numpy.float64, freq=None, observed='END', startIndex=None,mask=ma.nomask):
+
+ if freq is None: raise ValueError("freq not specified")
+
+ super(TimeSeries, self).__init__(values, dtype, startIndex,mask)
+ self.freq = corelib.fmtFreq(freq)
+ self.observed = corelib.fmtObserv(observed)
+ self.dtype = dtype
+
+ def __getitem__(self, key):
+ if isinstance(key,tsdate.Date):
+ if self.freq != key.freq:
+ raise "series of frequency "+str(self.freq)+" given date expression of type "+str(key.freq)
+ else:
+ key = int(key)
+ return super(TimeSeries, self).__getitem__(key)
+
+ def __setitem__(self, key, value):
+ if isinstance(key, tsdate.Date):
+ key = int(key)
+ super(TimeSeries, self).__setitem__(key,value)
+
+
+ def convert(self, freq, observed=None):
+ # return self converted to freq, method according to self.observed
+ toFreq = corelib.fmtFreq(freq)
+ fromFreq = self.freq
+
+ if fromFreq != toFreq:
+ if observed is None: observed=self.observed
+ else: observed = corelib.fmtObserv(observed)
+
+ firstIndex = sa.first_unmasked(self.data)
+ if firstIndex is None:
+ return TimeSeries([],dtype=self.dtype,freq=toFreq,observed=observed)
+
+ startIndexAdj = self.firstValue()
+
+ lastIndex = sa.last_unmasked(self.data)
+
+ tempData = copy.deepcopy(self.data[firstIndex:lastIndex+1])
+ tempMask = tempData.mask
+ tempData = tempData.filled()
+
+ cRetVal = cseries.reindex(tempData, fromFreq, toFreq, observed, startIndexAdj,tempMask)
+ _values = cRetVal['values']
+ _mask = cRetVal['mask']
+
+ startIndex = cseries.convert(startIndexAdj, fromFreq, toFreq)
+
+ return TimeSeries(_values,dtype=self.data.dtype,freq=toFreq,observed=observed,startIndex=startIndex, mask=_mask)
+
+ else:
+ return copy.deepcopy(self)
+
+
+ def __str__(self):
+ retVal = ""
+ if self.firstValue() is not None:
+ for i in range(self.firstValue(),self.lastValue()+1):
+ index = str(tsdate.Date(freq=self.freq,val=i))
+ index = index + (" " * (6-len(index)))
+ retVal += index + "---> " + str(super(TimeSeries, self).__getitem__(i)) + "\n"
+ return retVal
+ else:
+ return "<no data>"
+
+
+ ### DATA
+
+ def __add__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__add__(other),self.freq,self.observed)
+
+ def __radd__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__add__(other),self.freq,self.observed)
+
+ def __sub__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__sub__(other),self.freq,self.observed)
+
+ def __rsub__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__rsub__(other),self.freq,self.observed)
+
+ def __mul__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__mul__(other),self.freq,self.observed)
+
+ def __rmul__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__rmul__(other),self.freq,self.observed)
+
+ def __div__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__div__(other),self.freq,self.observed)
+
+ def __rdiv__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__rdiv__(other),self.freq,self.observed)
+
+ def __pow__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__pow__(other),self.freq,self.observed)
+
+ ### IN PLACE
+
+ def __iadd__(self, other):
+ validOpInputs(self,other)
+ self = SAtoTS(super(TimeSeries, self).__add__(other),self.freq,self.observed)
+ return self
+
+ def __isub__(self, other):
+ validOpInputs(self,other)
+ self = SAtoTS(super(TimeSeries, self).__sub__(other),self.freq,self.observed)
+ return self
+
+ def __imul__(self, other):
+ validOpInputs(self,other)
+ self = SAtoTS(super(TimeSeries, self).__mul__(other),self.freq,self.observed)
+ return self
+
+ def __idiv__(self, other):
+ validOpInputs(self,other)
+ self = SAtoTS(super(TimeSeries, self).__div__(other),self.freq,self.observed)
+ return self
+
+ # this overrides & and should only be used by boolean series
+ def __and__(self, other):
+ validOpInputs(self,other)
+ return self * other
+
+ # this overrides | and should only be used by boolean series
+ def __or__(self, other):
+ validOpInputs(self,other)
+ return ~(~self & ~other)
+
+ # this overrides ~ and should only be used by boolean series
+ # it is our "not" operator
+ def __invert__(self):
+ return self == False
+
+ ### COMPARISON
+
+ def __eq__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__eq__(other),self.freq,self.observed)
+
+ def __le__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__le__(other),self.freq,self.observed)
+
+ def __lt__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__lt__(other),self.freq,self.observed)
+
+ def __ge__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__ge__(other),self.freq,self.observed)
+
+ def __gt__(self, other):
+ validOpInputs(self,other)
+ return SAtoTS(super(TimeSeries, self).__gt__(other),self.freq,self.observed)
+
+def tser(start,end):
+ if start.freq != end.freq:
+ raise ValueError("start and end dates must have same frequency!")
+ return TimeSeries(numpy.arange(int(start),int(end)+1),dtype=corelib.freqTypeMapping[start.freq],freq=start.freq,observed='END',startIndex=int(start))
+
+def validOpInputs(ser1,ser2):
+ if isinstance(ser1,TimeSeries) and isinstance(ser2,TimeSeries) and ser1.freq != ser2.freq:
+ raise "operation cannot be performed on series with different frequencies ("+str(ser1.freq) + " and " + str(ser2.freq)+")"
+
+
+def SAtoTS(values,freq,observed,dtype=None):
+ if dtype is None: _dtype = values.dtype
+ else: _dtype = dtype
+ return TimeSeries(values.data,dtype=_dtype,freq=freq,observed=observed,startIndex=values.indexZeroRepresents)
+
+
+# math functions (two series)
+def add(ser1,ser2,fill_value=ma.masked):
+ return apply_func_twoseries(ma.add,ser1,ser2,fill_value)
+
+def multiply(ser1,ser2,fill_value=ma.masked):
+ return apply_func_twoseries(ma.multiply,ser1,ser2,fill_value)
+
+def divide(ser1,ser2,fill_value=ma.masked):
+ return apply_func_twoseries(ma.divide,ser1,ser2,fill_value)
+
+def subtract(ser1,ser2,fill_value=ma.masked):
+ return apply_func_twoseries(ma.subtract,ser1,ser2,fill_value)
+
+# math functions (one series, return series)
+def sqrt(ser):
+ return apply_func_oneseries(ma.sqrt,ser)
+
+# math functions (one series, return scalar)
+def sum(ser):
+ return ma.sum(ser.data)
+
+def product(ser):
+ return ma.product(ser.data)
+
+def average(ser):
+ return ma.average(ser.data)
+
+def where(condition,x,y):
+ tempResult = ma.where(condition.data,x,y)
+ return TimeSeries(tempResult,dtype=numpy.bool_,freq=condition.freq,observed=condition.observed,startIndex=condition.indexZeroRepresents)
+
+# generic functions
+def apply_func_twoseries(func,ser1,ser2,fill_value=ma.masked):
+ validOpInputs(ser1,ser2)
+ return SAtoTS(doFunc(ser1,ser2,func,fill_value=fill_value),ser1.freq,ser1.observed)
+
+def apply_func_oneseries(func,ser):
+ return SAtoTS(doFunc_oneseries(ser,func),ser.freq,ser.observed)
+
Added: trunk/Lib/sandbox/timeseries/timeseries.pyc
===================================================================
(Binary files differ)
Property changes on: trunk/Lib/sandbox/timeseries/timeseries.pyc
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/Lib/sandbox/timeseries/tsdate.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tsdate.py 2006-12-08 05:13:33 UTC (rev 2369)
+++ trunk/Lib/sandbox/timeseries/tsdate.py 2006-12-08 16:05:35 UTC (rev 2370)
@@ -0,0 +1,290 @@
+import corelib
+import mx.DateTime
+import numpy
+
+class Date:
+ def __init__(self,freq,year=None, month=None, day=None, seconds=None,quarter=None, date=None, val=None):
+
+ if hasattr(freq,'freq'):
+ self.freq = corelib.fmtFreq(freq.freq)
+ else:
+ self.freq = corelib.fmtFreq(freq)
+ self.type = corelib.freqToType(self.freq)
+
+ if val is not None:
+ if self.freq == 'D':
+ self.__date = val+originDate
+ elif self.freq == 'B':
+ self.__date = originDate + val + (val//5)*7 - (val//5)*5
+ elif self.freq == 'S':
+ self.__date = secondlyOriginDate + mx.DateTime.DateTimeDeltaFromSeconds(val)
+ elif self.freq == 'M':
+ self.__date = originDate + mx.DateTime.RelativeDateTime(months=val, day=-1)
+ elif self.freq == 'A':
+ self.__date = originDate + mx.DateTime.RelativeDateTime(years=val, month=-1, day=-1)
+ elif self.freq == 'Q':
+ self.__date = originDate + 1 + mx.DateTime.RelativeDateTime(years=int(val/4), month=int(12 * (float(val)/4 - val/4)), day=-1)
+ elif date is not None:
+ self.__date = date
+ else:
+ error = ValueError("Insufficient parameters given to create a date at the given frequency")
+
+ if year is None:
+ raise error
+
+ if self.freq in ('B','D'):
+ if month is None or day is None: raise error
+ elif self.freq == 'M':
+ if month is None: raise error
+ day = -1
+ elif self.freq == 'Q':
+ if quarter is None: raise error
+ month = quarter * 3
+ day = -1
+ elif self.freq == 'A':
+ month = -1
+ day = -1
+ elif self.freq == 'S':
+ if month is None or day is None or seconds is None: raise error
+
+ if self.freq != 'S':
+ self.__date = mx.DateTime.Date(year, month, day)
+ if self.freq == 'B':
+ if self.__date.day_of_week == 5 or self.__date.day_of_week == 6:
+ raise ValueError("Weekend passed as business day")
+ else:
+ _hours = int(seconds/3600)
+ _minutes = int((seconds - _hours*3600)/60)
+ _seconds = seconds % 60
+
+ self.__date = mx.DateTime.Date(year, month, day, _hours, _minutes, _seconds)
+
+
+ def day(self): return self.getDate().day
+ def day_of_week(self): return self.getDate().day_of_week
+ def month(self): return self.getDate().month
+ def quarter(self): return monthToQuarter(self.getDate().month)
+ def year(self): return self.getDate().year
+ def seconds(self): return int(self.getDate().second)
+ def minute(self): return int(self.getDate().minute)
+ def hour(self): return int(self.getDate().hour)
+
+ def strfmt(self,fmt):
+ qFmt = fmt.replace("%q","XXXX")
+ tmpStr = self.__date.strftime(qFmt)
+ return tmpStr.replace("XXXX",str(self.quarter()))
+
+ def __str__(self):
+ if self.freq in ("B","D"):
+ return self.__date.strftime("%d-%b-%y")
+ elif self.freq == "S":
+ return self.__date.strftime("%d-%b-%Y %H:%M:%S")
+ elif self.freq == "M":
+ return self.__date.strftime("%b-%Y")
+ elif self.freq == "Q":
+ return str(self.year())+"q"+str(self.quarter())
+ elif self.freq == "A":
+ return str(self.year())
+ else:
+ return self.__date.strftime("%d-%b-%y")
+
+
+ def __add__(self, other):
+ if isinstance(other, Date):
+ raise TypeError("Cannot add dates")
+ return Date(freq=self.freq, val=int(self) + other)
+
+ def __radd__(self, other): return self+other
+
+ def __sub__(self, other):
+ try: return self + (-1) * other
+ except: pass
+ try:
+ if self.freq <> other.freq:
+ raise ValueError("Cannont subtract dates of different frequency (" + str(self.freq) + " <> " + str(other.freq) + ")")
+ return int(self) - int(other)
+ except TypeError:
+ raise TypeError("Could not subtract types " + str(type(self)) + " and " + str(type(other)))
+
+ def __repr__(self): return "<" + str(self.freq) + ":" + str(self) + ">"
+
+ def __eq__(self, other):
+ if self.freq <> other.freq:
+ raise TypeError("frequencies are not equal!")
+ return int(self) == int(other)
+
+ def __cmp__(self, other):
+ if self.freq <> other.freq:
+ raise TypeError("frequencies are not equal!")
+ return int(self)-int(other)
+
+ def __hash__(self): return hash(int(self)) ^ hash(self.freq)
+
+ def __int__(self):
+ return self.value()
+
+ def value(self):
+ if self.freq == 'D':
+ return int((self.__date-originDate).days)
+ elif self.freq == 'B':
+ days = (self.__date-originDate).days
+ weeks = days // 7
+ return int((weeks*5) + (days - weeks*7))
+ elif self.freq == 'M':
+ return (self.__date.year - originDate.year)*12 + (self.__date.month - originDate.month)
+ elif self.freq == 'S':
+ return int((self.__date - secondlyOriginDate).seconds)
+ elif self.freq == 'A':
+ return int(self.__date.year - originDate.year + 1)
+ elif self.freq == 'Q':
+ return int ((self.__date.year - originDate.year)*4 + (self.__date.month - originDate.month)/3)
+
+ def mxDate(self):
+ return self.__date
+
+originDate = mx.DateTime.Date(1850)-1
+secondlyOriginDate = mx.DateTime.Date(1980) - mx.DateTime.DateTimeDeltaFromSeconds(1)
+
+
+#######################
+# FUNCTIONS
+#######################
+def monthToQuarter(monthNum):
+ return int((monthNum-1)/3)+1
+
+def thisday(freq):
+
+ freq = corelib.fmtFreq(freq)
+
+ tempDate = mx.DateTime.now()
+
+ # if it is Saturday or Sunday currently, freq==B, then we want to use Friday
+ if freq == 'B' and tempDate.day_of_week >= 5:
+ tempDate -= (tempDate.day_of_week - 4)
+ if freq == 'B' or freq == 'D' or freq == 'S':
+ return Date(freq, date=tempDate)
+ elif freq == 'M':
+ return Date(freq,tempDate.year,tempDate.month)
+ elif freq == 'Q':
+ return Date(freq,tempDate.year,quarter=monthToQuarter(tempDate.month))
+ elif freq == 'A':
+ return Date(freq,tempDate.year)
+
+def prevbusday(day_end_hour=18,day_end_min=0):
+ tempDate = mx.DateTime.localtime()
+
+ dateNum = tempDate.hour + float(tempDate.minute)/60
+ checkNum = day_end_hour + float(day_end_min)/60
+
+ if dateNum < checkNum: return thisday('B') - 1
+ else: return thisday('B')
+
+
+# returns _date converted to a date of _destFreq according to _relation
+# _relation = "BEFORE" or "AFTER" (not case sensitive)
+def dateOf(_date,_destFreq,_relation="BEFORE"):
+
+ _destFreq = corelib.fmtFreq(_destFreq)
+ _rel = _relation.upper()[0]
+
+ if _date.freq == _destFreq:
+ return _date
+ elif _date.freq == 'D':
+
+ if _destFreq == 'B':
+ # BEFORE result: preceeding Friday if _date is a weekend, same day otherwise
+ # AFTER result: following Monday if _date is a weekend, same day otherwise
+ tempDate = _date.mxDate()
+ if _rel == "B":
+ if tempDate.day_of_week >= 5: tempDate -= (tempDate.day_of_week - 4)
+ elif _rel == "A":
+ if tempDate.day_of_week >= 5: tempDate += 7 - tempDate.day_of_week
+ return Date(freq='B',date=tempDate)
+
+ elif _destFreq == 'M': return Date('M',_date.mxDate().year,_date.mxDate().month)
+
+ elif _destFreq == 'S':
+ if _rel == "B": return Date('S',_date.mxDate().year,_date.mxDate().month,_date.mxDate().day,0)
+ elif _rel == "A": return Date('S',_date.mxDate().year,_date.mxDate().month,_date.mxDate().day,24*60*60-1)
+
+ elif _destFreq == 'Q': return Date('Q',_date.mxDate().year,quarter=monthToQuarter(_date.mxDate().month))
+
+ elif _destFreq == 'A': return Date('A',_date.mxDate().year)
+
+ elif _date.freq == 'B':
+
+ if _destFreq == 'D': return Date('D',_date.mxDate().year,_date.mxDate().month,_date.mxDate().day)
+
+ elif _destFreq == 'M': return Date('M',_date.mxDate().year,_date.mxDate().month)
+
+ elif _destFreq == 'S':
+ if _rel == "B": return Date('S',_date.mxDate().year,_date.mxDate().month,_date.mxDate().day,0)
+ elif _rel == "A": return Date('S',_date.mxDate().year,_date.mxDate().month,_date.mxDate().day,24*60*60-1)
+
+ elif _destFreq == 'Q': return Date('Q',_date.mxDate().year,quarter=monthToQuarter(_date.mxDate().month))
+
+ elif _destFreq == 'A': return Date('A',_date.mxDate().year)
+
+ elif _date.freq == 'M':
+
+ if _destFreq == 'D':
+ tempDate = _date.mxDate()
+ if _rel == "B":
+ return Date('D',_date.mxDate().year,_date.mxDate().month,1)
+ elif _rel == "A":
+ if _date.mxDate().month == 12:
+ tempMonth = 1
+ tempYear = _date.mxDate().year + 1
+ else:
+ tempMonth = _date.mxDate().month + 1
+ tempYear = _date.mxDate().year
+ return Date('D',tempYear,tempMonth,1)-1
+
+ elif _destFreq == 'B':
+ if _rel == "B": return dateOf(dateOf(_date,'D',"BEFORE"),'B',"AFTER")
+ elif _rel == "A": return dateOf(dateOf(_date,'D',"AFTER"),'B',"BEFORE")
+
+ elif _destFreq == 'S':
+ if _rel == "B": return dateOf(dateOf(_date,'D',"BEFORE"),'S',"BEFORE")
+ elif _rel == "A": return dateOf(dateOf(_date,'D',"AFTER"),'S',"AFTER")
+
+ elif _destFreq == 'Q': return Date('Q',_date.mxDate().year,quarter=monthToQuarter(_date.mxDate().month))
+
+ elif _destFreq == 'A': return Date('A',_date.mxDate().year)
+
+ elif _date.freq == 'S':
+
+ if _destFreq == 'D':
+ return Date('D',_date.mxDate().year,_date.mxDate().month,_date.mxDate().day)
+ elif _destFreq == 'B':
+ if _rel == "B": return dateOf(dateOf(_date,'D'),'B',"BEFORE")
+ elif _rel == "A": return dateOf(dateOf(_date,'D'),'B',"AFTER")
+ elif _destFreq == 'M':
+ return Date('M',_date.mxDate().year,_date.mxDate().month)
+
+ elif _date.freq == 'Q':
+
+ if _destFreq == 'D':
+ if _rel == "B": return dateOf(_date-1,'D',"AFTER")+1
+ elif _rel == "A": return Date('D',_date.mxDate().year,_date.mxDate().month,_date.mxDate().day)
+ elif _destFreq == 'B':
+ if _rel == "B": return dateOf(dateOf(_date,'D'),'B',"AFTER")
+ if _rel == "A": return dateOf(dateOf(_date,'D',"AFTER"),'B',"BEFORE")
+ elif _destFreq == 'M':
+ if _rel == "B": return dateOf(_date-1,'M',"AFTER")+1
+ elif _rel == "A": return Date('M',_date.mxDate().year,_date.mxDate().month)
+ elif _destFreq == 'A': return Date('A',_date.mxDate().year)
+ elif _date.freq == 'A':
+
+ if _destFreq == 'D':
+ if _rel == "B": return Date('D',_date.mxDate().year, 1, 1)
+ elif _rel == "A": return Date('D',_date.mxDate().year,12,31)
+ elif _destFreq == 'B':
+ if _rel == "B": return dateOf(dateOf(_date,'D'),'B',"AFTER")
+ if _rel == "A": return dateOf(dateOf(_date,'D',"AFTER"),'B',"BEFORE")
+ elif _destFreq == 'M':
+ if _rel == "B": return Date('M',_date.mxDate().year,1)
+ elif _rel == "A": return Date('M',_date.mxDate().year,12)
+ elif _destFreq == 'Q':
+ if _rel == "B": return Date('Q',_date.mxDate().year,quarter=1)
+ elif _rel == "A": return Date('Q',_date.mxDate().year,quarter=4)
\ No newline at end of file
Added: trunk/Lib/sandbox/timeseries/tsdate.pyc
===================================================================
(Binary files differ)
Property changes on: trunk/Lib/sandbox/timeseries/tsdate.pyc
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
More information about the Scipy-svn
mailing list