Unit, Sun & Moon Services

Tokenless public DNS services for unit conversion, solar events, and lunar phase.

Overview

ResolveDB ships three tokenless public services in the public.v1 namespace. Their answers are unmetered and cacheable through standard DNS and DoH wire; the DoH JSON endpoint is HTTP no-store. Unit conversion is pure computation. Moon calculations are local, but an omitted date means the current UTC date. Sun calculations are local after location resolution; city, IP, and what3words inputs can require an external location provider, and solar results change by date.

ServiceResourceWhat it returns
Unit conversionunitsA value converted between two units in the same category
SunsunSunrise, sunset, solar noon, civil twilight, day length
MoonmoonMoon phase, illumination, age, next full/new moon

Try any of these live in the Query Console or the Try It Live runner.

Shared Answering Status

The shared answering contract is implemented for units, sun, and moon in the repository: v=rdb1;s=ok;t=data; precedes their flat fields, so generic SDK decoders can consume them. Native DNS and DoH preserve values, RCODEs, TTLs, and requested signatures/proofs; signing failure returns SERVFAIL. Units use TTL 86400, moon TTL 3600, with no payload TTL hint. Credentials and unsupported operations are REFUSED before semantic validation; valid non-TXT requests yield NODATA, malformed parameters FORMERR. Sun has TTL at most 3600, capped at the next UTC midnight. Its location provider failures remain SERVFAIL and valid unknown locations return NODATA. Case-stable Base32/hex query encoding is implemented. Resource versions are canonical v[1-9][0-9]* within DNS label/name bounds; public lookups explicitly support only v1 and never downgrade a requested version. Hosted versions are exact customer identities. This implementation status does not imply a production deployment.


Unit Conversion

Convert a numeric value between two units in the same category. Cross-category conversions (e.g. length to mass) are rejected.

Query Format

# Single params label: <value>-<from>-to-<to>
dig TXT get.100-c-to-f.units.public.v1.resolvedb.net +short

# DoH (HTTPS) JSON API
curl -s "https://doh.resolvedb.io/resolve?name=get.100-c-to-f.units.public.v1.resolvedb.net&type=TXT" | jq

The value uses DNS-safe encoding: d is the decimal point and a leading n is a negative sign (DNS labels cannot contain . or a leading -).

You wantValue tokenExample query
0.50d5get.0d5-c-to-f.units...
-40n40get.n40-c-to-f.units...
55get.5-km-to-mi.units...

Categories & Unit Slugs

CategoryUnit slugs
temperaturec (celsius), f (fahrenheit), k (kelvin)
lengthm, km, cm, mm, mi, yd, ft, in
masskg, g, mg, t (tonne), lb, oz
volumel, ml, gal (US), qt (US), floz (US)
speedms (m/s), kmh, mph, kn (knot)

Examples

# Temperature: 100 C to F
dig TXT get.100-c-to-f.units.public.v1.resolvedb.net +short

# Length: 5 km to miles
dig TXT get.5-km-to-mi.units.public.v1.resolvedb.net +short

# Mass: 1 lb to kg
dig TXT get.1-lb-to-kg.units.public.v1.resolvedb.net +short

# Volume: 1 US gallon to litres
dig TXT get.1-gal-to-l.units.public.v1.resolvedb.net +short

# Speed: 60 mph to km/h
dig TXT get.60-mph-to-kmh.units.public.v1.resolvedb.net +short

Response Format

v=rdb1;s=ok;t=data;in=100;from=celsius;to=fahrenheit;r=212;cat=temperature

Response Fields

FieldDescriptionExample
inInput value (parsed)100
fromCanonical source unit namecelsius
toCanonical target unit namefahrenheit
rConversion result (6 significant figures)212
catUnit categorytemperature

Errors

CauseResult
Malformed expression (not <value>-<from>-to-<to>)FormErr
Invalid numeric value (NaN, exponent, double decimal)FormErr
Unknown unit slugFormErr
Units in different categoriesFormErr

Sun

Sunrise, sunset, solar noon, civil twilight, and day length for a location on the current UTC day. The location grammar is identical to the weather service.

Query Format

# By city name
dig TXT get.london.sun.public.v1.resolvedb.net +short

# By coordinates (d = decimal point, _ separates lat/lon)
dig TXT get.40d7128_-74d0060.sun.public.v1.resolvedb.net +short

# By IP geolocation
dig TXT get.ip-8-8-8-8.sun.public.v1.resolvedb.net +short

# By what3words (hyphens replace dots)
dig TXT get.w3w-filled-count-soap.sun.public.v1.resolvedb.net +short

# DoH (HTTPS)
curl -s "https://doh.resolvedb.io/resolve?name=get.london.sun.public.v1.resolvedb.net&type=TXT" | jq

Location Input Formats

FormatExampleDescription
City nameget.london.sun...City name, hyphens for multi-word
Coordinatesget.51d5074_-0d1278.sun...Lat/lon with d as decimal, _ separator
IP addressget.ip-8-8-8-8.sun...Location of the IP
what3wordsget.w3w-filled-count-soap.sun...3m x 3m precision

Response Format

v=rdb1;s=ok;t=data;rise=2024-09-01T05:13:00Z;set=2024-09-01T18:42:00Z;noon=2024-09-01T11:57:00Z;dawn=2024-09-01T04:40:00Z;dusk=2024-09-01T19:15:00Z;daylen=13h29m

Response Fields

FieldDescriptionExample
riseSunrise (ISO 8601 UTC)2024-09-01T05:13:00Z
setSunset (ISO 8601 UTC)2024-09-01T18:42:00Z
noonSolar noon (always present)2024-09-01T11:57:00Z
dawnCivil dawn (ISO 8601 UTC)2024-09-01T04:40:00Z
duskCivil dusk (ISO 8601 UTC)2024-09-01T19:15:00Z
daylenDay length (XhYm)13h29m

Polar Day & Night

At high latitudes a day may have no sunrise or sunset. In that case the response replaces rise/set with a single polar field, and daylen reflects the extreme. Solar noon is always defined.

# Midnight sun (Svalbard, June solstice)
v=rdb1;s=ok;t=data;polar=day;noon=2024-06-21T11:00:00Z;daylen=24h0m

# Polar night (Svalbard, December solstice)
v=rdb1;s=ok;t=data;polar=night;noon=2024-12-21T11:00:00Z;daylen=0h0m
FieldDescriptionExample
polarday (midnight sun) or night (polar night)day

Moon

Moon phase, illuminated fraction, age, and the next full and new moon dates. Location-independent.

Query Format

# Today (UTC) — no params
dig TXT get.moon.public.v1.resolvedb.net +short

# A specific UTC date (strict YYYY-MM-DD)
dig TXT get.2024-01-25.moon.public.v1.resolvedb.net +short

# DoH (HTTPS)
curl -s "https://doh.resolvedb.io/resolve?name=get.2024-01-25.moon.public.v1.resolvedb.net&type=TXT" | jq

The date label must be exactly YYYY-MM-DD with a four-digit unsigned year. Leap years and month lengths are checked; a malformed or impossible date returns FormErr. An omitted date selects the current UTC day, represented by noon UTC; the default date changes at midnight.

Response Format

v=rdb1;s=ok;t=data;phase=Full Moon;illum=...;age=...;next_full=...;next_new=...

Response Fields

FieldDescriptionExample
phasePhase nameFull Moon
illumIlluminated fraction of the disc (0.0–1.0)0.999
ageAge in days since the last new moon14.8
next_fullDate of the next full moon (UTC)2024-02-24
next_newDate of the next new moon (UTC)2024-02-09

Phase Names

phase is one of eight canonical names:

New Moon, Waxing Crescent, First Quarter, Waxing Gibbous, Full Moon, Waning Gibbous, Last Quarter, Waning Crescent.


Parsing Responses

These three services use flat ;-separated key=value fields; units and moon also carry the ordinary success prefix. The small parsers below handle these flat results only. Use the SDK decoders for hosted d= payloads, escaped values, and other envelopes.

const dns = require('dns').promises;

async function query(qname) {
  const records = await dns.resolveTxt(qname);
  const response = records[0].join('');
  const fields = {};
  for (const part of response.split(';')) {
    const [key, value] = part.split('=');
    if (key) fields[key] = value;
  }
  return fields;
}

// Unit conversion
const conv = await query('get.100-c-to-f.units.public.v1.resolvedb.net');
console.log(`${conv.in} ${conv.from} = ${conv.r} ${conv.to}`); // 100 celsius = 212 fahrenheit

// Sunrise/sunset for London (today, UTC)
const sun = await query('get.london.sun.public.v1.resolvedb.net');
console.log(`Sunrise ${sun.rise}, sunset ${sun.set}, day ${sun.daylen}`);

// Moon phase for a date
const moon = await query('get.2024-01-25.moon.public.v1.resolvedb.net');
console.log(`${moon.phase} (${Math.round(moon.illum * 100)}% illuminated)`);
import dns.resolver

def query(qname):
    answers = dns.resolver.resolve(qname, 'TXT')
    response = b''.join(answers[0].strings).decode('utf-8')
    fields = {}
    for part in response.split(';'):
        if '=' in part:
            key, value = part.split('=', 1)
            fields[key] = value
    return fields

# 5 km to miles
conv = query('get.5-km-to-mi.units.public.v1.resolvedb.net')
print(f"{conv['in']} {conv['from']} = {conv['r']} {conv['to']}")

# Moon phase today
moon = query('get.moon.public.v1.resolvedb.net')
print(f"{moon['phase']}: {float(moon['illum']) * 100:.0f}% illuminated")

Next Steps