Tier 0 — Absolute Beginner

Temperature Converter

Convert between Celsius, Fahrenheit, and Kelvin — pure functions, error handling, and CLI args.

🐍 Python 🟨 JavaScript

1. The Problem

Build a temperature converter that takes a value and a unit (Celsius, Fahrenheit, or Kelvin) and converts it to all three scales instantly. Bonus: reject temperatures below absolute zero (−273.15 °C).

Why this project? Pure functions with clear maths, error handling, and floating-point rounding — all in one small program.

2. How to Think About This

Route everything through Celsius as the "hub" unit — convert input to Celsius first, then from Celsius to the other two. This means you only need 4 conversion formulas instead of 6:

  • C → F: multiply by 9/5 then add 32
  • F → C: subtract 32 then multiply by 5/9
  • C → K: add 273.15
  • K → C: subtract 273.15

3. The Build

Core logic (converter.mjs)

// Four conversion formulas — Celsius as the hub
export const C_to_F = c => (c * 9/5) + 32;
export const F_to_C = f => (f - 32) * 5/9;
export const C_to_K = c => c + 273.15;
export const K_to_C = k => k - 273.15;

// Convert from any unit to all three, rounding to 4 decimal places
export function convertAll(value, fromUnit) {
  // Step 1: convert to Celsius
  let celsius;
  switch (fromUnit) {
    case "C": celsius = value; break;
    case "F": celsius = F_to_C(value); break;
    case "K": celsius = K_to_C(value); break;
    default: throw new Error(`Unknown unit: "${fromUnit}". Use C, F, or K.`);
  }

  // Step 2: validate — nothing below absolute zero
  if (celsius < -273.15) {
    throw new RangeError(`${value}°${fromUnit} is below absolute zero (−273.15 °C).`);
  }

  // Step 3: convert to all three and return
  return {
    C: +celsius.toFixed(4),           // + converts string back to number
    F: +C_to_F(celsius).toFixed(4),
    K: +C_to_K(celsius).toFixed(4),
  };
}

Command-line interface (convert.mjs)

import { convertAll } from "./converter.mjs";

// Read arguments: node convert.mjs 100 C
const [,, rawValue, unit] = process.argv;

if (!rawValue || !unit) {
  console.error("Usage: node convert.mjs <value> <unit>");
  console.error("Example: node convert.mjs 100 C");
  process.exit(1);
}

const value = Number(rawValue);
if (isNaN(value)) { console.error("Value must be a number."); process.exit(1); }

try {
  const result = convertAll(value, unit.toUpperCase());
  console.log(`${value}°${unit.toUpperCase()} =`);
  console.log(`  ${result.C} °C`);
  console.log(`  ${result.F} °F`);
  console.log(`  ${result.K} K`);
} catch (e) {
  console.error("Error:", e.message);
  process.exit(1);
}

4. Test & Prove

converter.test.mjs
import { convertAll, C_to_F, F_to_C } from "./converter.mjs";

let pass = 0, fail = 0;
function test(desc, fn) {
  try { fn(); console.log("  ✓", desc); pass++; }
  catch(e) { console.log("  ✗", desc, "—", e.message); fail++; }
}
const approx = (a, b) => Math.abs(a - b) < 0.001;

test("water boils: 100°C = 212°F",   () => { const r = convertAll(100,"C"); if(!approx(r.F,212)) throw new Error(r.F); });
test("water freezes: 0°C = 32°F",    () => { const r = convertAll(0,"C");   if(!approx(r.F,32))  throw new Error(r.F); });
test("absolute zero: 0 K = −273.15°C", () => { const r = convertAll(0,"K"); if(!approx(r.C,-273.15)) throw new Error(r.C); });
test("body temp: 98.6°F ≈ 37°C",     () => { const r = convertAll(98.6,"F"); if(!approx(r.C,37)) throw new Error(r.C); });
test("below absolute zero throws",    () => { try { convertAll(-300,"C"); throw new Error("should throw"); } catch(e) { if(!(e instanceof RangeError)) throw e; } });
test("unknown unit throws",           () => { try { convertAll(100,"X");  throw new Error("should throw"); } catch(e) { if(!(e instanceof Error)) throw e; } });
console.log(`
${pass} passed, ${fail} failed`);

5. The Interface

Input: two command-line arguments — value (number) and unit (C/F/K). Case-insensitive.

Output: the value in all three scales, to 4 decimal places.

$ node convert.mjs 100 c
100°C =
  100 °C
  212 °F
  373.15 K

$ node convert.mjs -300 c
Error: −300°C is below absolute zero (−273.15 °C).

6. Run It

node convert.mjs 37 C     # body temperature
node convert.mjs 212 F    # water boiling (Fahrenheit in)
node convert.mjs 0 K      # absolute zero
node converter.test.mjs   # run tests

🎯 Try this next

  1. Add a browser UI — text input + dropdown for unit; display all three results live as the user types using the input event
  2. Add Rankine and Réaumur scales
  3. Validate to a sensible maximum (e.g. 15 million K is the core of the sun)
  4. Accept piped stdin: echo "100 C" | node convert.mjs

What you practised

Pure functions with a single responsibility, routing through a hub unit to minimise conversion formulas, process.argv for command-line arguments, custom error types (RangeError vs Error), and toFixed() + unary + for clean rounding.

Reference: Numbers & Math · Error Handling · Functions

Try It Yourself