How Falcon calculates night time automatically

Night time is one of those things that seems simple until you try to automate it. The sun goes down, you keep flying, those hours count differently. But figuring out exactly when the sun set relative to where your plane was at any given minute turns out to be a genuinely interesting problem.

Here is how we solved it.

The naive approach (and why it doesn't work)

At first glance you might think: just look up sunset at the departure airport and again at the arrival airport. If the flight crosses sunset, subtract.

The problem is your flight is moving. Departing Auckland at 6 PM local time heading west, the sun is setting behind you while the sky ahead is still light. A straight line between two sunset times ignores the fact that you covered 300 nautical miles in between. At those latitudes sunset can shift by minutes across that distance.

We needed per-minute precision along the actual route.

The algorithm

We use the Solar Position Algorithm, or SPA, developed by the National Renewable Energy Laboratory in the US. It is the same algorithm used by solar panel installers and astronomers. Feed it a time, a latitude, and a longitude, and it tells you exactly where the sun is in the sky.

The implementation comes from the spa Dart package, which is a direct port of the NREL reference code. It accounts for:

It is a lot of math for what boils down to a single question: is the sun more than 6 degrees below the horizon?

Why 6 degrees?

That is the civil twilight threshold. Aviation defines night as the period between the end of evening civil twilight and the beginning of morning civil twilight. Civil twilight ends when the sun's centre is 6 degrees below the horizon. That is the number we use.

You can find the constant at auto_night_calculator.dart line 6:

const _civilTwilightThreshold = -6.0;

How we sample the flight path

Once we have the departure and arrival airports with their coordinates (stored in the airports table as lat/lon), we divide the flight into one-minute segments:

final fraction = i / (numSamples == 0 ? 1 : numSamples);
final lat = depLat + (arrLat - depLat) * fraction;
final lon = depLon + (arrLon - depLon) * fraction;

For each minute we interpolate the position along a straight line between the two airports and ask SPA where the sun is. If the elevation is below -6 degrees, that minute counts as night.

This gives us a per-minute resolution across the whole flight. No guessing, no averaging, just a solid yes or no for every minute you were in the air.

The edge cases

A few things we had to handle:

Where to find the code

Everything lives in falcon/app/lib/utils/auto_night_calculator.dart. The SPA package dependency is declared in pubspec.yaml as spa: ^1.3.0. The bridge between the UI and the calculator is in flight_time_calculator.dart, and the dialog that pilots interact with lives in widgets/flights/dialogs/calculate_time_dialog.dart.

The result gets stored as an integer of minutes in the night_time column of the flights table.

Why we built it instead of using an API

Sunrise/sunset APIs exist. Most of them are free for low usage. But they introduce a network dependency for something that should work offline. Falcon is offline-first. Every calculation runs on device, no signal required. The SPA algorithm is deterministic and fast. On a modern phone it evaluates a single minute in under a millisecond.

We also did not want to rate-limit our users. If you are logging 500 flights offline on a long trip, you should not have to wait for an API quota to reset.

The result

When you enter a flight in Falcon and both airports have coordinates, the app automatically computes your night time in the background. No manual lookup, no mental arithmetic, no digging through tables. Just the right number, every time.

The code is open source. You can read it, test it, and tell us if we got something wrong. That is the whole point.