wttr/IMPERIAL_UNITS.md

3.2 KiB
Raw Blame History

Imperial Units Implementation

Overview

The application automatically selects between metric and imperial (USCS) units based on the request context, matching the behavior of the original Python implementation.

Unit Selection Priority

The system determines which units to use in the following priority order:

  1. Explicit query parameter (highest priority)

    • ?u - Force imperial units (°F, mph, inches, inHg)
    • ?m - Force metric units (°C, km/h, mm, hPa)
  2. Language parameter

    • ?lang=us - Use imperial units (for us.wttr.in subdomain)
  3. Client IP geolocation

    • Requests from US IP addresses automatically use imperial units
    • Uses GeoIP database to detect country code
  4. Default

    • Metric units for all other cases

Implementation Details

Code Changes

  1. GeoIP Module (src/location/geoip.zig)

    • Added isUSIP() method to detect US IP addresses
    • Queries MaxMind database for country ISO code
    • Returns true if country code is "US"
  2. Handler (src/http/handler.zig)

    • Added geoip to HandleWeatherOptions
    • Implements priority logic for unit selection
    • Extracts client IP from headers (X-Forwarded-For, X-Real-IP)
    • Passes use_imperial flag to all renderers
  3. Renderers (all updated to support imperial units)

    • ansi.zig - Shows °F instead of °C
    • line.zig - Shows °F and mph for formats 1-4
    • custom.zig - Converts all units (temp, wind, precip, pressure)
    • v2.zig - Shows imperial units in detailed format
    • json.zig - Already outputs both units (no changes needed)

Conversions

  • Temperature: °F = °C × 9/5 + 32
  • Wind speed: mph = km/h × 0.621371
  • Precipitation: inches = mm × 0.0393701
  • Pressure: inHg = hPa × 0.02953

Testing

Unit Tests

All renderers have unit tests verifying imperial units:

  • test "render with imperial units" in ansi.zig
  • test "format 2 with imperial units" in line.zig
  • test "render custom format with imperial units" in custom.zig
  • test "render v2 format with imperial units" in v2.zig
  • test "imperial units selection logic" in handler.zig
  • test "isUSIP detects US IPs" in geoip.zig

Integration Testing

# Test with lang=us
curl "http://localhost:8002/London?lang=us&format=2"
# Output: 51.5074,-0.1278: ☁️ 54°F 🌬SW19mph

# Test with explicit ?u
curl "http://localhost:8002/London?format=2&u"
# Output: 51.5074,-0.1278: ☁️ 54°F 🌬SW19mph

# Test metric override
curl "http://localhost:8002/London?lang=us&format=2&m"
# Output: 51.5074,-0.1278: ☁️ 12°C 🌬SW30km/h

# Test from US IP (automatic detection)
curl -H "X-Forwarded-For: 1.1.1.1" "http://localhost:8002/London?format=2"
# Output: Uses imperial as 1.1.1.1 is detected as US IP

Documentation Updates

  • API_ENDPOINTS.md - Added "Unit System Defaults" section explaining priority
  • README.md - Updated "Implemented Features" to mention auto-detection
  • IMPERIAL_UNITS.md - This document

Compatibility

This implementation matches the original Python behavior in lib/parse_query.py:

  • Same priority order
  • Same detection logic
  • Same unit conversions
  • Compatible with existing clients and scripts