Calculating Inflated Prices with CPI and Groovy
There have been a few occasions where I have wanted to express historic prices in terms of their inflated value or vice-versa.. e.g. $100 dollars in 2007 was worth about $63 in 1990.

This is actually a very simple thing to calculate... we take the CPI from 2007 (207.34) and the CPI from 1990 (130.65) and do the computation thusly:

$100.0 * (1.0 + ((130.65833333333333 - 207.3424166666667) / 207.3424166666667))

I have written a grails service that grabs the latest CPI data and does this for me... it's just groovy, so it should be easy to use outside of a grails app.

class InflationService {
    boolean transactional = true

    // this is where the live CPI data lives
    String cpiURL = 'ftp://ftp.bls.gov/pub/special.requests/cpi/cpiai.txt'

    // map of year to CPI average String -> double
    def cpiMap = [:]

    // track the last time we updated from the source data,
    // for long lived apps we don't want to get stale.
    long lastLoadTime = 0;

    // always use the current year as the target year
    double calculateCurrentDollars(String fromYear, double value) {
        refreshCPIData(false)

        GregorianCalendar date = new GregorianCalendar()
        def year = date.get(Calendar.YEAR)

        // not sure what the CPI table looks like in january...
        // this should account for no record for the current year...
        // more that 1 missing year is a serious problem
        def toYear = String.valueOf((cpiMap[String.valueOf(year)] != null) ? year : year-1)

        return calculateYearDollars(fromYear, toYear, value)
    }

    double calculateYearDollars(String fromYear, String toYear, double value) {
        refreshCPIData(false)

        def toCPI = cpiMap[toYear]
        def fromCPI = cpiMap[fromYear]
        // here's the actual math...
        // pretty simple when you final get down to it :)
        // TODO - check for nulls or zeros and throw exception.
        return value * (1.0 + ((toCPI - fromCPI) / fromCPI))
    }

    // refresh cpiMap if last update was more than 1 day ago
    // OR forceUpdateNow param is true.
    public void refreshCPIData(boolean forceUpdateNow) {
        long oneDay = (1000 * 60 * 60 * 24)
        // update once per day. (or if forced)
        if (forceUpdateNow || (lastLoadTime + oneDay) < System.currentTimeMillis()) {
            lastLoadTime = System.currentTimeMillis()

            // grab the "tabular" data right from The Man
            cpiURL.toURL().text.eachLine {yearLine ->
                // find all the lines that start with a year..
                // these are the useful bits of the doc
                if (yearLine.matches(/^\s+\d\d\d\d\s.*/)) {
                    // split the line up into individual values
                    def yearList = yearLine.split(/\s+/).findAll {it.size() > 0}
                    // the first item is the year.. hang onto that
                    def year = yearList[0]
                    // the rest of the values are CPI values for each month
                    // (some averages at the end that we ignore)
                    yearList = yearList.tail().collect {Double.valueOf(it)}
                    // average all 12 months for every year...
                    // except the current year could have less than 12 months
                    int idx = yearList.size() < 12 ? yearList.size() - 1 : 11;
                    cpiMap[year] = yearList[0..idx].sum() / (idx + 1)
                }
            }
        }
    }
}
here is a simple test.
class InflationServiceTests extends GroovyTestCase {
    InflationService inflationService;

    void test2007to1990Dollars() {
        assertEquals('got wrong answer', 63.01572800870056,inflationService.calculateYearDollars('2007', '1990', 100.0));
    }
}

It shouldn't matter which direction you want to do the conversion in.. 1990 dollars to 2007 dollars or 2007 dollars to 1990 dollars. The data starts in 1913 (the year the federal reserve was created) and runs about a month behind.. so I write this in September 2008 and the CPI is available through August 2008.
 
 
 
 
Home
RSS Feed
About

My Projects


Tags

blog brother charity code colbert comic cpi cringly doctorow education funny g4 gov govrake groovy house inflation itunes legislation little maine obama podcast politics prediction president python roller rss sad search senate skeptoid syntaxhighlighter systems techtv ted transparency video wii


Last 40 Posts



© dan



login