Update Calculator Currency Rates via Perl Script


Square Dot Square Dot Square Dot Little red trilobyte thingy Square Dot Square Dot Square Dot

Calculator no longer updates its currency rates over the internet. Generally, it will crash or "Unexpectedly Quit". The currency conversion rates are kept in a plain text property list file, or plist called FinancialRates.plist. Here's how you can update the currency conversion rates with a Perl script.

Before Using This Script

I wrote this for my own use, so it's a bit crude. For example, it doesn't parse the date in the IMF file for the time of the last update, but uses its own date. So even if the IMF doesn't update its file, Calculator will show the last updated time as the time you last ran this script.

Also, if the IMF doesn't have a currency listed, or doesn't have an exchange value for one of its listed currencies, the currency won't be available in Calculator's menu. That's because this script doesn't check to see whether there's an old value in the current file. It just re-writes the file every time you run it.

If, for some reason, you decide to go back to the default currency values, you can always just delete or rename the FinancialRates.plist file. Calculator will no longer see it, and will use a FinancialRates.plist file that's stored in the Calculator application's bundle.

The Perl Script

The process of updating the FinancialRates.plist can be automated via a Perl script. As written, the script is meant to be put into the Library/Application Support/Calculator in your Home folder. If the Calculator folder doesn't exist on your computer, you need to make it. If it's not there, it just means you never successfully updated the currency rates from the Calculator application.

If you want to put the script somewhere else, you'll need to either fix the path where the file is saved, or move the FinancialRates.plist file into the proper folder once it's been updated, as the default behavior is to save it in the same folder as the script.

Copy this script and paste it into a text editor and save it with a name like UpdateCurrencyRates.pl. The script must be saved as plain text with Unix line endings.

#!/usr/bin/perl

# Fetch currency values from the IMF and save them out for Calculator.app
# 9/27/2005

use strict;
use POSIX qw(strftime);
use File::Basename;

print qq(Fetching data...\n);

my @lines = eval { `curl -sS http://www.imf.org/external/np/fin/rates/rms_rep_pt.cfm` };

my $outdir=dirname($0);

# Save the file in the same folder as the script:
open (OUTFILE, ">$outdir/FinancialRates.plist") or die "Can't open output file for writing: $!\n";

# show the status:
print qq(Writing out file...);

# print the header:
print OUTFILE <<HERE;
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Currency</key>
	<array>
HERE

my $updatetime = strftime("%Y-%m-%d %H:%M:%S %z", localtime(time));

# loop thru the lines of the TSV file:
foreach my $line (@lines)
{
	# get rid of any junk at the end of the line:
	$line =~ s/(\r\n|\r|\n)//;
	
	# just do lines with three values separated by tabs:
	if ( $line =~ m/(.+)\t(.+)\t(.+)/ )
	{
		my ($currency, $note, $value) = split(/\t/, $line);

		# strip out the quotation marks around the TSVs:
		$currency =~ s/^\"(.+)\"$/$1/;
		$currency =~ s/&/&amp;/g;
		
		$value =~ s/^\"(.+)\"$/$1/;
		$value =~ s/^\w+//;

		# skip lines that don't have a value:
		next if (  $value =~ m/^\-\-\-/);
		
		if ( ! ($note =~ m/\(1\)/) or ($note =~ m/\(2\)/) )
		{
			# needs to be inverted:
			$value = 1.0 /$value;
		}
		else
		{
			# just strip out the white space and use it as-is:
			$value =~ s/^\s+//;
		}
		
		print OUTFILE qq(\t\t<string>$currency</string>\n);
		print OUTFILE qq(\t\t<string>$value</string>\n);
		print OUTFILE qq(\t\t<string>$updatetime</string>\n);
		
	}
}

$updatetime = strftime("%d %b %Y %I:%M  %p", localtime(time));

print OUTFILE <<HERE;
	</array>
	<key>Last Updated</key>
	<string>$updatetime</string>
</dict>
</plist>
HERE

close OUTFILE;

print qq(Finished.\n);

Once you've saved the script, make sure the Calculator app isn't open. Then, open the Terminal application in your Utilities folder and navigate to the folder where you saved the script. Run it like this from the Terminal:

perl UpdateCurrencyRates.pl

Hit the enter key and wait a few moments. You should see a couple of status messages. Once the command prompt comes back, your new currency rates should be written out. Now you open up Calculator and use your new currency rates!

How Calculator Stores Financial Rates

Calculator stores its current rates in a file called FinancialRates.plist in the user's ~/Library/Application Support folder called Calculator. If you've never successfully updated the currency rates, you'll have to create this folder yourself.

It's a simple XML plist file, and can easily be edited by hand, though it's a bit tedious. The file has the currency name on one line, followed by the value in U.S. dollars, followed by the last date it was updated. An abbreviated version looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Currency</key>
	<array>
		<string>Euro</string>
		<string>1.153500</string>
		<string>2003-07-03 08:05:41 -0700</string>
		<string>Japanese yen</string>
		<string>0.008389</string>
		<string>2003-07-03 08:05:41 -0700</string>
		<string>Pound sterling</string>
		<string>1.663700</string>
		<string>2003-07-03 08:05:41 -0700</string>
		<string>U.S. dollar</string>
		<string>1.000000</string>
		<string>2003-07-03 08:05:41 -0700</string>
		.
		.
		.
	</array>
	<key>Last Updated</key>
	<string>05 Jul 2002 01:35  PM</string>
</dict>
</plist>

Deep Background

I figured the URLs out by subjecting the executable inside the Calculator.app bundle to this command:

strings Calculator | grep http

That command causes Calculator to cough up this URL:
http://si.info.apple.com/services/exchangeRates.xml
It's this file that appears to be damaged or corrupt, since there's a bunch of odd characters at the top, and it doesn't look like well-formed XML to me.

A look at that URL showed some kind of XML file with a script in it that's simply a redirection to this page at the IMF:
http://www.imf.org/external/np/fin/rates/rms_rep.cfm

Charlie Minow
February 9, 2020 - 5:09 PM MST

Dot Dot Dot Rose Thing Dot Dot Dot
Cool doo wah