Skip to content

Instantly share code, notes, and snippets.

@clemlesne
Created May 31, 2025 11:32
Show Gist options
  • Save clemlesne/7496ba0b6a6ec173a7aa6367e90e9233 to your computer and use it in GitHub Desktop.
Save clemlesne/7496ba0b6a6ec173a7aa6367e90e9233 to your computer and use it in GitHub Desktop.
Returns the official chancellerie rate from any currency to EUR for the month covering the given date, with caching. In Google Sheets Apps Script.
/**
* Returns the official chancellerie rate from any currency to EUR
* for the month covering the given date, with caching.
*
* @param {Date} inputDate A Date object from the sheet.
* @param {String} currency The three-letter ISO currency code (e.g. "USD").
* @return {Number|String} The monthly rate (e.g. 1.1373) or an error message.
* @customfunction
*/
function GET_CHANCELLERY_RATE(inputDate, currency) {
// 1. Validate inputs
if (!(inputDate instanceof Date)) {
return '⚠️ Please provide a valid date.';
}
if (typeof currency !== 'string' || currency.length !== 3) {
return '⚠️ Please provide a three-letter currency code.';
}
currency = currency.toUpperCase();
// 2. Prepare cache
var cache = CacheService.getScriptCache(); // Script-wide cache instance (https://developers.google.com/apps-script/reference/cache/cache-service)
var periodKey = currency + '_' + inputDate.getFullYear() + '-' + (inputDate.getMonth()+1);
var cachedValue = cache.get(periodKey);
if (cachedValue !== null) {
// Return cached rate immediately
return parseFloat(cachedValue);
}
// 3. Fetch from API with fallback
var url = 'https://ec.europa.eu/budg/inforeuro/api/public/currencies/' + currency;
var records;
try {
var response = UrlFetchApp.fetch(url);
if (response.getResponseCode() !== 200) {
throw new Error('HTTP ' + response.getResponseCode());
}
records = JSON.parse(response.getContentText());
} catch (e) {
// On API failure, return cache if it existed, else error
if (cachedValue !== null) {
return parseFloat(cachedValue);
}
return '⚠️ Unable to fetch rate and no cache available.';
}
// 4. Find matching period in records
var rate = null;
for (var i = 0; i < records.length; i++) {
var rec = records[i];
var [sd, sm, sy] = rec.dateStart.split('/').map(Number);
var [ed, em, ey] = rec.dateEnd.split('/').map(Number);
var startDate = new Date(sy, sm-1, sd);
var endDate = new Date(ey, em-1, ed);
if (inputDate >= startDate && inputDate <= endDate) {
rate = rec.amount;
break;
}
}
if (rate === null) {
return '⚠️ No rate found for ' + currency + ' on that date.';
}
// 5. Cache the result for 6 hours (max TTL) (https://developers.google.com/apps-script/reference/cache)
cache.put(periodKey, rate.toString(), 6 * 60 * 60);
return rate;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment