Created
May 31, 2025 11:32
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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