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.
| Service | Resource | What it returns |
|---|---|---|
| Unit conversion | units | A value converted between two units in the same category |
| Sun | sun | Sunrise, sunset, solar noon, civil twilight, day length |
| Moon | moon | Moon 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" | jqThe 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 want | Value token | Example query |
|---|---|---|
0.5 | 0d5 | get.0d5-c-to-f.units... |
-40 | n40 | get.n40-c-to-f.units... |
5 | 5 | get.5-km-to-mi.units... |
Categories & Unit Slugs
| Category | Unit slugs |
|---|---|
temperature | c (celsius), f (fahrenheit), k (kelvin) |
length | m, km, cm, mm, mi, yd, ft, in |
mass | kg, g, mg, t (tonne), lb, oz |
volume | l, ml, gal (US), qt (US), floz (US) |
speed | ms (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 +shortResponse Format
v=rdb1;s=ok;t=data;in=100;from=celsius;to=fahrenheit;r=212;cat=temperatureResponse Fields
| Field | Description | Example |
|---|---|---|
in | Input value (parsed) | 100 |
from | Canonical source unit name | celsius |
to | Canonical target unit name | fahrenheit |
r | Conversion result (6 significant figures) | 212 |
cat | Unit category | temperature |
Errors
| Cause | Result |
|---|---|
Malformed expression (not <value>-<from>-to-<to>) | FormErr |
| Invalid numeric value (NaN, exponent, double decimal) | FormErr |
| Unknown unit slug | FormErr |
| Units in different categories | FormErr |
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" | jqLocation Input Formats
| Format | Example | Description |
|---|---|---|
| City name | get.london.sun... | City name, hyphens for multi-word |
| Coordinates | get.51d5074_-0d1278.sun... | Lat/lon with d as decimal, _ separator |
| IP address | get.ip-8-8-8-8.sun... | Location of the IP |
| what3words | get.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=13h29mResponse Fields
| Field | Description | Example |
|---|---|---|
rise | Sunrise (ISO 8601 UTC) | 2024-09-01T05:13:00Z |
set | Sunset (ISO 8601 UTC) | 2024-09-01T18:42:00Z |
noon | Solar noon (always present) | 2024-09-01T11:57:00Z |
dawn | Civil dawn (ISO 8601 UTC) | 2024-09-01T04:40:00Z |
dusk | Civil dusk (ISO 8601 UTC) | 2024-09-01T19:15:00Z |
daylen | Day 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| Field | Description | Example |
|---|---|---|
polar | day (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" | jqThe 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
| Field | Description | Example |
|---|---|---|
phase | Phase name | Full Moon |
illum | Illuminated fraction of the disc (0.0–1.0) | 0.999 |
age | Age in days since the last new moon | 14.8 |
next_full | Date of the next full moon (UTC) | 2024-02-24 |
next_new | Date 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
- Query Console — run these services live, no setup
- GeoIP & Location — the shared location grammar
- UQRP Protocol — query and response format