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.