Cycling time estimator
40 km at an average of 20 km/h is 2 hours on the bike: the estimator divides distance by average speed and shows the result in hours, in minutes and as an hours-and-minutes label. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Distance
- 40
- Average riding speed
- 20
- Riding time hours
- 2
- Riding time minutes
- 120
- Riding time formatted
- 2h
A cycling time estimator answers the simple planning question every rider asks before a commute, club ride, or gran fondo: if I cover this distance at this average speed, how long will I be on the bike? Enter a positive ride distance and a strictly positive average speed in matching units—kilometers with kilometers per hour, or miles with miles per hour—and the tool returns pure riding time as decimal hours, total minutes, a compact hour-and-minute string, the closed formula used, and step-by-step substitution you can check by hand.
What cycling riding time means and how it is computed
Estimated riding time for a bike trip is the pure moving duration you would spend if you held a constant average speed over the whole distance, with no rest stops, traffic lights, or elevation model baked in. Average speed here is the mean over the moving portion of the ride, not peak sprint speed and not the GPS speed that includes long café stops.
That distinction matters for planning: if your training software reports an average that already folds in pauses, feeding that number here underestimates on-bike time; if you use a pure rolling average from a computer, the estimate matches seat time more closely. The tool does not convert units for you—mixing miles of distance with kilometers per hour of speed produces a number that is mathematically fine but physically wrong—so callers must keep the pair consistent.
Teachers, coaches, and app authors care about the zero-speed rejection as much as the happy path: a speed of zero or a negative value cannot define a finite duration, and a silent fallback would hide bad sensor data or a missing default.
What you can do with it
Commute and club-ride planning
Riders enter route distance and a realistic average speed to estimate seat time before choosing a start time or booking post-ride logistics.
Training week duration budgets
Coaches convert planned weekly kilometers into estimated hours on the bike at the athlete’s known average pace for load planning.
FAQ
What happens when average speed is zero or negative?
Zero or negative speed cannot produce a finite ride duration.
Do I need matching units for distance and speed?
Yes. Use km with km/h or miles with mph. The tool does not convert mixed units for you.
Does this include rest stops or hills?
No. It estimates pure moving time at a constant average speed. Add your own break time outside this capability if needed.
Is the cycling time estimator free?
The browser tool is free and runs locally.
Which average speed should I enter?
Use your moving average, not your peak sprint speed or a GPS average that includes long café stops. A rolling average from a bike computer gives the estimate closest to your real time in the saddle.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/travel/cycling-time \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"distance":40,"average_speed":20}'const res = await fetch("https://api.kit.forhosting.com/travel/cycling-time", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"distance": 40,
"average_speed": 20
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/travel/cycling-time",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"distance": 40,
"average_speed": 20
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/travel/cycling-time", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"distance":40,"average_speed":20}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"distance":40,"average_speed":20}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/travel/cycling-time", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"distance": 40,
"average_speed": 20
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "travel.cycling_time",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_distance | 1000000 |
max_speed | 10000 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Zero or negative average speed is rejected with a clear invalid_input error because division by a non-positive speed is not a ride plan.
What cycling riding time means and how it is computed
The closed formula is riding_time equals distance divided by average_speed, where distance and average_speed share the same unit system: forty kilometers at twenty kilometers per hour is two hours; twenty-five miles at twelve and a half miles per hour is also two hours. On success the response echoes rounded distance and average_speed, publishes riding_time_hours and riding_time_minutes with fixed twelve-decimal rounding, sets riding_time_formatted to a compact human string such as two hours thirty minutes, and includes formula and steps so worksheets and automated tests can assert every intermediate line.
How to call the API and what comes back
Send a JSON body with two required finite numbers: distance (aliases dist, d, length, total_distance, ride_distance) and average_speed (aliases speed, avg_speed, v, velocity, ride_speed). Distance must be strictly positive and at most one million; average_speed must be strictly positive and at most ten thousand per hour so intermediate quotients stay finite in IEEE double precision on the Worker and in the browser. On success the response echoes rounded distance and average_speed, sets riding_time_hours to distance divided by average_speed, riding_time_minutes to that value times sixty, riding_time_formatted to a compact hour-and-minute label built from whole minutes after rounding, formula to the string riding_time equals distance divided by average_speed, message to a short English summary, and steps to an ordered array of substitution lines. Failed validation—missing fields, non-finite numbers, values outside published limits, zero or negative distance, zero or negative average_speed, or a non-finite quotient—returns invalid_input and is never charged. Pricing is a flat $0.002 per successful request with unit item and zero marginal unit price. Prefer numeric JSON fields when you control the client; string numbers are accepted only when they match a strict finite numeric pattern without units or trailing text.
Practical tips, limits, and related searches
Typical recreational averages fall between twelve and twenty-five kilometers per hour; trained road groups often sit higher, and e-bike assist can push averages further—still well under the catalog maximum. Prefer this capability when you already know distance and a planned or historical average speed and only need pure riding duration; if your source is a GPS track, extract distance and moving average first. Keep distance and average_speed inside the published ranges so the quotient cannot overflow into a non-finite riding time that the solver must reject. When teaching or testing, pair examples: forty kilometers at twenty kilometers per hour yields two hours and a clean two-hour formatted string; thirty kilometers at fifteen kilometers per hour yields two hours as well; ninety minutes of seat time can be recovered from forty-five kilometers at thirty kilometers per hour; and average_speed equal to zero demonstrates the hard invalid_input path that protects against divide-by-zero. This landing targets people searching for a cycling time estimator, bike ride duration, or average speed distance calculator for bicycles; it is not a road-trip car ETA tool, not a multi-stop itinerary planner, and not a calorie or power model. Failed tasks that return invalid_input do not consume prepaid balance, which keeps exploratory scripts cheap when you deliberately probe the zero-speed error. Round-trip checks are easy: recompute distance divided by average_speed by hand and confirm it equals riding_time_hours within the same twelve-decimal rounding, and confirm that riding_time_minutes equals that value times sixty after the same rounding policy.
Integration use cases
Unit tests for ride-planning apps
Generate known-good distance–speed–duration triples plus deliberate zero-speed rejections for mobile and backend expected values.
Technical questions
How is cycling riding time calculated?
Riding time equals distance divided by average_speed when both are positive and share the same unit system (for example km with km/h). The API also returns minutes and a compact hour–minute string.