Skip to content

Instantly share code, notes, and snippets.

@tomastraveltime
Created May 12, 2025 09:09
Show Gist options
  • Save tomastraveltime/12bfd22cfe5435edf9b768dfa41e90d1 to your computer and use it in GitHub Desktop.
Save tomastraveltime/12bfd22cfe5435edf9b768dfa41e90d1 to your computer and use it in GitHub Desktop.
Code running two point comparison on https://traveltime.com/accuracy
import { Client, TravelMode } from '@googlemaps/google-maps-services-js';
import axios from 'axios';
import { Coords, TravelTimeClient } from 'traveltime-api';
const travelTimeSdk = new TravelTimeClient({
apiKey: process.env.TT_APP_KEY || '',
applicationId: process.env.TT_APP_ID || '',
});
const googleClient = new Client();
const oxfordLocation = {
label: 'Oxford, UK',
coords: {
lat: 51.7520131,
lng: -1.2578499,
},
country: 'gb' as const,
};
const birminghamLocation = {
label: 'Birmingham, UK',
coords: {
lat: 52.4796992,
lng: -1.9026911,
},
country: 'gb' as const,
};
type TwoPointComparisonResponse = Array<{
travelTime: number
provider: string
}>
type Task = (coordsFrom: Coords, coordTo: Coords, date: Date) => Promise<{ provider: string, travelTime: number }>
const getNextMidweekNoon = () => {
const now = new Date();
const nextMidweek = new Date(now);
const targetDay = 3;
let daysToAdd = (targetDay - now.getDay() + 7) % 7;
if (daysToAdd === 0 && now.getHours() >= 12) {
daysToAdd = 7;
}
nextMidweek.setDate(now.getDate() + daysToAdd);
nextMidweek.setHours(12, 0, 0, 0);
return nextMidweek;
};
async function calculateResponseTime(fnc: () => Promise<number>) {
try {
const travelTime = await fnc();
return travelTime;
} catch (error) {
return -1;
}
}
const ttTask: Task = async (coordsFrom, coordsTo, date) => {
const fnc = async () => {
const res = await travelTimeSdk.routes({
departure_searches: [{
id: 'quick',
arrival_location_ids: ['to'],
departure_location_id: 'from',
departure_time: date.toISOString(),
properties: ['travel_time'],
transportation: {
type: 'driving',
},
snapping: {
penalty: 'disabled',
},
}],
locations: [
{ id: 'from', coords: coordsFrom },
{ id: 'to', coords: coordsTo },
],
});
return res.results[0].locations[0].properties[0].travel_time ?? -1;
};
const travelTime = await calculateResponseTime(fnc);
return {
travelTime,
provider: 'TravelTime',
};
};
const googleTask: Task = async (coordsFrom, coordsTo, date) => {
const fnc = async () => {
const res = await googleClient.distancematrix({
params: {
key: process.env.GOOGLE_API_KEY || 'Google API Key',
origins: [coordsFrom],
destinations: [coordsTo],
departure_time: date,
mode: TravelMode.driving,
},
});
return res.data.rows[0].elements[0].duration.value;
};
const travelTime = await calculateResponseTime(fnc);
return {
travelTime,
provider: 'Google',
};
};
const tomTomTask: Task = async (coordsFrom, coordsTo, date) => {
const fnc = async () => {
const res = await axios.get(
`https://api.tomtom.com/routing/1/calculateRoute/${coordsFrom.lat},${coordsFrom.lng}:${coordsTo.lat},${coordsTo.lng}/json`,
{
params: {
key: process.env.TOM_TOM_API_KEY,
travelMode: 'car',
departAt: date.toISOString(),
},
},
);
return res.data.routes[0].summary.travelTimeInSeconds;
};
const travelTime = await calculateResponseTime(fnc);
return {
travelTime,
provider: 'TomTom',
};
};
const hereTask: Task = async (coordsFrom, coordsTo, date) => {
const fnc = async () => {
const res = await axios.post(
`https://matrix.router.hereapi.com/v8/matrix?async=false&apiKey=${process.env.HERE_API_KEY}`,
{
origins: [coordsFrom],
destinations: [coordsTo],
departureTime: date.toISOString(),
regionDefinition: {
type: 'world',
},
transportMode: 'car',
},
);
return res.data.matrix.travelTimes[0];
};
const travelTime = await calculateResponseTime(fnc);
return {
travelTime,
provider: 'HERE',
};
};
const mapBoxTask: Task = async (coordsFrom, coordsTo) => {
const fnc = async () => {
const res = await axios.get(
`https://api.mapbox.com/directions-matrix/v1/mapbox/driving/${coordsFrom.lng},${coordsFrom.lat};${coordsTo.lng},${coordsTo.lat}`,
{
params: {
access_token: process.env.MAP_BOX_API_KEY,
},
},
);
return res.data.durations[0][1];
};
const travelTime = await calculateResponseTime(fnc);
return {
travelTime,
provider: 'Mapbox',
};
};
let cachedResponse: null | TwoPointComparisonResponse = null;
async function run(from: Coords, to: Coords) {
try {
if (typeof from !== 'object' || !('lat' in from) || !('lng' in from) || typeof to !== 'object' || !('lat' in to) || !('lng' in to)) {
throw new Error('Malformed request');
}
const isDefaultConfig = from.lat === birminghamLocation.coords.lat && from.lng === birminghamLocation.coords.lng && to.lat === oxfordLocation.coords.lat && to.lng === oxfordLocation.coords.lng;
if (isDefaultConfig && cachedResponse) {
return cachedResponse;
}
const date = getNextMidweekNoon();
const params: Parameters<Task> = [from, to, date];
const tasks = Promise.allSettled([
googleTask(...params),
ttTask(...params),
tomTomTask(...params),
hereTask(...params),
mapBoxTask(...params),
]);
const results = (await tasks).filter((_) => _.status === 'fulfilled').map<TwoPointComparisonResponse[number]>((_) => (_ as PromiseFulfilledResult<TwoPointComparisonResponse[number]>).value);
if (isDefaultConfig) {
cachedResponse = results;
setTimeout(() => {
cachedResponse = null;
}, 1000 * 60 * 60 * 24);
}
return results;
} catch (error) {
throw new Error('Error in task execution');
}
}
run(birminghamLocation.coords, oxfordLocation.coords);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment