Block time
Runnable examples for estimating gate-to-gate block time using SkyLink's ML model. See ML Flight Time Estimation for model details, accuracy metrics, and supported aircraft types.
| # | Question | Data used |
|---|---|---|
| 1 | Estimate block time for KJFK → KLAX on a B738 | GET /ml/flight-time |
| 2 | Compare flight times across 4 routes from EGLL | GET /ml/flight-time |
Requirements
x-api-key on every request (direct subscription). Learn more →Install
The scripts below use requests for API calls and rich for terminal output. Install once:
pip install requests rich1. Block time estimate: KJFK → KLAX on B738
Question: What is the estimated gate-to-gate block time for a 737-800 on the KJFK–KLAX route?
The model returns an estimated time plus a min/max range derived from historical data (GradientBoosting, R²≈0.98). Wind is not modelled — actual times will vary with routing and conditions.
import os
import requests
from rich.console import Console
from rich.panel import Panel
console = Console()
HEADERS = {
"X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
"X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"
def fetch_flight_time(
origin: str, destination: str, aircraft: str | None = None
) -> dict | None:
params: dict[str, str] = {"from": origin, "to": destination}
if aircraft:
params["aircraft"] = aircraft
r = requests.get(
f"{BASE}/ml/flight-time",
headers=HEADERS,
params=params,
timeout=(10, 15),
)
if r.status_code == 404:
return None
r.raise_for_status()
return r.json()
def fmt_mins(minutes: int | None) -> str:
if minutes is None:
return "—"
return f"{minutes // 60}h {minutes % 60:02d}m"
def main() -> None:
data = fetch_flight_time("KJFK", "KLAX", aircraft="B738")
if not data:
console.print("[red]No estimate returned.[/red]")
return
origin = data.get("origin", "KJFK")
dest = data.get("destination", "KLAX")
aircraft = data.get("aircraft_type", "B738")
est_display = data.get("estimated_hours_display") or fmt_mins(
data.get("estimated_minutes")
)
min_m = data.get("min_minutes")
max_m = data.get("max_minutes")
distance = data.get("distance_nm")
range_str = f"{fmt_mins(min_m)} – {fmt_mins(max_m)}"
body = (
f"Route: [bold]{origin} → {dest}[/bold]\n"
f"Aircraft: {aircraft}\n"
f"Estimated: [bold green]{est_display}[/bold green]\n"
f"Range: {range_str}\n"
f"Distance: {distance:,.1f} nm" if distance else ""
)
console.print(Panel(body, title="Block Time Estimate", style="blue"))
console.print(
"[dim]Estimate is statistical average for this route/type — "
"actual time varies with winds and routing.[/dim]"
)
if __name__ == "__main__":
main()Output: A panel showing route, aircraft type, estimated block time (display format), min–max range, and great-circle distance in nautical miles.
2. Route comparison from EGLL
Question: How do flight times from London Heathrow compare across four long-haul destinations?
Fetch all four routes concurrently and sort by estimated time ascending. Useful for schedulers identifying tight connection windows.
import os
import concurrent.futures
import requests
from rich.console import Console
from rich.table import Table
console = Console()
HEADERS = {
"X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
"X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"
ROUTES = [
("EGLL", "KJFK"),
("EGLL", "OMDB"),
("EGLL", "YSSY"),
("EGLL", "RJTT"),
]
def fetch_flight_time(origin: str, destination: str) -> tuple[str, str, dict | None]:
try:
r = requests.get(
f"{BASE}/ml/flight-time",
headers=HEADERS,
params={"from": origin, "to": destination},
timeout=(10, 15),
)
if r.status_code == 404:
return origin, destination, None
r.raise_for_status()
return origin, destination, r.json()
except Exception as exc: # noqa: BLE001
console.print(f"[red]{origin}→{destination}: {exc}[/red]")
return origin, destination, None
def fmt_mins(minutes: int | None) -> str:
if minutes is None:
return "—"
return f"{minutes // 60}h {minutes % 60:02d}m"
def main() -> None:
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool:
results = list(pool.map(lambda r: fetch_flight_time(*r), ROUTES))
valid = [
(orig, dest, d)
for orig, dest, d in results
if d and d.get("estimated_minutes") is not None
]
valid.sort(key=lambda x: x[2].get("estimated_minutes", 0))
table = Table(
title="EGLL Long-haul Route Comparison (model default aircraft)",
show_lines=True,
)
table.add_column("Route", style="cyan", no_wrap=True)
table.add_column("Distance (nm)", justify="right")
table.add_column("Est. Time", justify="center", style="bold")
table.add_column("Min", justify="center")
table.add_column("Max", justify="center")
for orig, dest, d in valid:
distance = d.get("distance_nm")
dist_str = f"{distance:,.0f}" if distance else "—"
table.add_row(
f"{orig} → {dest}",
dist_str,
fmt_mins(d.get("estimated_minutes")),
fmt_mins(d.get("min_minutes")),
fmt_mins(d.get("max_minutes")),
)
console.print(table)
console.print(
"[dim]Statistical estimates — wind not modelled. "
"Routes sorted by estimated time ascending.[/dim]"
)
if __name__ == "__main__":
main()Output: A table sorted shortest-to-longest showing route, distance in nautical miles, estimated time, and the historical min/max range for each city pair.