DEV Community

Cover image for Weather Math for Developers: Dew Point, Heat Index, Wind Chill, and Unit Conversions in Code
Bellal Hossain
Bellal Hossain

Posted on

Weather Math for Developers: Dew Point, Heat Index, Wind Chill, and Unit Conversions in Code

If you've ever built a weather widget, a dashboard, or an IoT project, you've hit this: the raw sensor value is easy, but the number users actually care about ("feels like", dew point, wind in the right units) needs a formula, and formulas have rules.

Here are the calculations I see developers get wrong most often, with short working examples and the pitfalls to watch for.

1. Convert units in one place

Weather data arrives in mixed units: Celsius or Fahrenheit, km/h, mph, knots, m/s. The safest pattern is to pick one base unit internally and convert only at the edges.

const cToF = (c) => (c * 9) / 5 + 32;
const fToC = (f) => ((f - 32) * 5) / 9;
const cToK = (c) => c + 273.15;

// Wind: convert everything through m/s
const TO_MS = {
  ms: 1,
  kmh: 1 / 3.6,
  mph: 0.44704,
  knot: 1852 / 3600,
  fts: 0.3048,
};

const convertWind = (value, from, to) =>
  (value * TO_MS[from]) / TO_MS[to];

convertWind(30, "knot", "kmh"); // 55.56
cToF(100);                      // 212
cToK(0);                        // 273.15
Enter fullscreen mode Exit fullscreen mode

Quick sanity checks: one knot is 1.852 km/h, and one mph is 1.609344 km/h. If you want an independent check on your output, the temperature converter covers Celsius, Fahrenheit, Kelvin, Rankine and Réaumur, and the wind speed converter covers km/h, mph, m/s, knots, ft/s and the Beaufort scale.

2. Dew point with the Magnus formula

Relative humidity depends on temperature, so it's a poor way to describe how much moisture is in the air. Dew point is more direct. A common approximation is the Magnus formula:

function dewPointC(tempC, rhPercent) {
  const b = 17.625;
  const c = 243.04;
  const gamma = Math.log(rhPercent / 100) + (b * tempC) / (c + tempC);
  return (c * gamma) / (b - gamma);
}

dewPointC(30, 70); // ≈ 23.9
Enter fullscreen mode Exit fullscreen mode

Pitfalls:

  • rhPercent is a percentage (70), not a fraction (0.7). Passing the wrong one gives a nonsense result.
  • The formula is an approximation tuned for typical atmospheric ranges, so don't expect lab precision at extremes.
  • Use rhPercent > 0, because Math.log(0) is -Infinity.

You can compare your output with the dew point calculator. Small differences of a few tenths of a degree are normal because tools may use different coefficient sets.

3. Heat index: know the valid range

The heat index estimates how hot it feels by combining temperature and humidity. A widely used approach is the Rothfusz regression, which takes temperature in Fahrenheit:

function heatIndexF(t, rh) {
  // Regression is intended for hot, humid conditions
  if (t < 80 || rh < 40) return null;

  return (
    -42.379 +
    2.04901523 * t +
    10.14333127 * rh -
    0.22475541 * t * rh -
    0.00683783 * t * t -
    0.05481717 * rh * rh +
    0.00122874 * t * t * rh +
    0.00085282 * t * rh * rh -
    0.00000199 * t * t * rh * rh
  );
}

heatIndexF(90, 70); // ≈ 105.8 °F  (about 41 °C)
Enter fullscreen mode Exit fullscreen mode

So 90 °F (about 32 °C) at 70% humidity feels closer to 106 °F (about 41 °C).

Pitfalls:

  • The coefficients expect Fahrenheit. Feeding in Celsius gives garbage without any error.
  • Outside roughly 80 °F and 40% humidity, the regression isn't meant to be used, so return null or fall back to the plain temperature rather than showing a misleading number.
  • It's a perceived-conditions estimate, not a measurement.

To check your implementation, try the heat index calculator.

4. Wind chill: the opposite validity range

Wind chill estimates how cold air feels on exposed skin. A commonly used formula takes temperature in Celsius and wind speed in km/h:

def wind_chill_c(temp_c: float, wind_kmh: float):
    # Intended for cold air and a noticeable breeze
    if temp_c > 10 or wind_kmh <= 4.8:
        return None
    v = wind_kmh ** 0.16
    return 13.12 + 0.6215 * temp_c - 11.37 * v + 0.3965 * temp_c * v

print(round(wind_chill_c(-5, 30), 1))  # -13.0
Enter fullscreen mode Exit fullscreen mode

Pitfalls:

  • The wind speed unit matters. Passing mph into a km/h formula quietly gives the wrong answer, which is another reason to centralize conversions.
  • Don't apply wind chill in warm weather, and don't apply heat index in cold weather.

You can compare against the wind chill calculator.

5. Beaufort scale and UV categories: lookups, not formulas

Some weather values are categories mapped from ranges. A small lookup keeps your UI consistent.

// Beaufort scale (0-12) from wind speed in km/h
const BEAUFORT_UPPER_KMH = [1, 6, 12, 20, 29, 39, 50, 62, 75, 89, 103, 118];

function beaufort(kmh) {
  const i = BEAUFORT_UPPER_KMH.findIndex((limit) => kmh < limit);
  return i === -1 ? 12 : i;
}

beaufort(30); // 5

// UV index categories (WHO-style bands)
function uvCategory(uv) {
  if (uv < 3) return "Low";
  if (uv < 6) return "Moderate";
  if (uv < 8) return "High";
  if (uv < 11) return "Very high";
  return "Extreme";
}

uvCategory(7); // "High"
Enter fullscreen mode Exit fullscreen mode

For cross-checking, see the UV index tool, which explains levels and recommended sun protection. Keep in mind that UV can be significant even on cloudy or cool days, so don't base sun advice on cloud cover alone.

6. Sunrise and sunset: use a library, then verify

Solar times depend on latitude, longitude and date, because the Sun's apparent position changes across the year and across the Earth's surface. The calculation is involved enough that a tested library is usually the right call (SunCalc for JavaScript and Astral for Python are popular options).

Two things to watch:

  • Time zones. Compute in UTC and convert for display.
  • High latitudes, where in some seasons there may be no sunrise or sunset on a given day. Handle that case in your UI instead of assuming a value exists.

When you want a quick reference value to compare your output against, the sunrise and sunset calculator gives sunrise, sunset, solar noon and daylight duration for locations around the world.

Don't confuse calculations with forecasts

A calculator applies a formula to values you supply. A forecast comes from observations, atmospheric models and uncertainty. If your app shows calculated values next to forecast data, label them clearly, and for severe weather alerts always defer to official sources. For quick reference views of live conditions and upcoming days, there are world weather and weather forecast pages.

Quick checklist

  1. Are all inputs converted to a single base unit?
  2. Is humidity a percentage or a fraction, and does the formula agree?
  3. Is the formula applied inside its valid temperature and humidity range?
  4. Is each formula getting the unit it expects (°F vs °C, km/h vs mph)?
  5. Do solar times account for time zones and polar edge cases?
  6. Does the UI make clear what's calculated and what's forecast?

Free tools for quick checks

When a number looks off, I like to verify it independently before changing code. The Noloii Weather & Climate Tools collection is free and runs in the browser. The ones I use most for testing:

What's the weirdest weather-data bug you've run into? Tell me in the comments.

Top comments (0)