Perch
Lua APIperch.time, json, storage

perch.time, json, storage

The always-on utility namespaces — zoned time, JSON, and the per-mod key-value store.

2 min readUpdated Jul 21, 2026

perch.time — always granted

Pure, no scope needed. Backed by the platform’s full IANA time-zone database.

perch.time.now(zone?)

local t = perch.time.now()              -- system local time
local tk = perch.time.now("Asia/Tokyo") -- any IANA zone

Returns a table:

FieldMeaning
hour min sec24-hour clock fields
year mon daycalendar date (mon 1–12)
dowday of week, 0 = Sunday
offUTC offset in minutes, DST-correct

An unknown zone returns { error = "unknown zone" } — check before trusting fields when the zone string is user input.

perch.time.format(fmt, zone?)

perch.time.format("%H:%M")                   -- "17:42"
perch.time.format("%A, %B %e", "Europe/Paris")

Formats now in the given zone with a std::format chrono spec (%H %M %S %A %B %d %p…). Returns "?" on a bad spec or zone.

perch.json — always granted

local tbl = perch.json.decode(body)   -- string → table, nil-ish on bad JSON
local str = perch.json.encode(tbl)    -- table → string

The bridge between perch.http.get bodies and Lua tables. decode of invalid JSON returns nothing — guard it:

local data = perch.json.decode(body)
if not data then return end

perch.storage — scope storage

perch.storage.set("history", { 3, 4, 6, 9 })
local hist = perch.storage.get("history")   -- nil if never set
  • Per-mod, persisted across restarts, invisible to other mods.
  • Values are JSON-shaped: tables, strings, numbers, booleans.
  • 64 KB total cap — a write that would exceed it is discarded, so keep it for state, not caches of fetched data.

The wider guidance on what belongs in storage vs settings vs pushes: Settings & storage.

esc
Type to search
navigate open