Pulp EngineDocument Rendering
Get started

Number and date formatting

Formatting helpers work in HTML/PDF, DOCX, PPTX, CSV and XLSX. Set renderConfig.locale on a template, or pass options.locale and options.timeZone for a render. A string locale sets language, number, currency and date tags together; an object merges fields individually.

{"options":{"locale":"de-DE","timeZone":"Europe/Berlin"}}

Number tags fall back through number, language, currency, en-US. Currency uses currency, language, en-US; dates use date, language, en-AU. The default currency code is USD; set locale.currencyCode to change it.

Code Meaning Default decimal places Example (en-US)
N Grouped number 2 N2: 1,234.50
F Fixed without grouping 2 F1: 1234.5
D Integer, padded to the supplied width 0 D6: 000042
P Percent from a ratio 0 P1: 12.3%
C Currency ISO minor units C with JPY: ¥1,235
A Accounting currency ISO minor units A2: ($42.00)
E Scientific 3 E2: 1.23E6
K Compact at most 1 K1: 1.3M
B SI bytes (base 1000) at most 1 B1: 12.5 kB

Codes are case insensitive; precision is 0–20. Use {{formatNumber amount "N2"}}, {{formatNumber amount "C2" "EUR"}}, {{percent ratio 1}}, {{compact amount}}, {{bytes size}}, or {{ordinal rank}}. Ordinal suffixes currently support English.

For 1234567.891, N2 produces 1,234,567.89 in en-US, 1.234.567,89 in de-DE, and 1 234 567,89 in fr-FR (narrow no-break spaces).

currency now respects ISO minor units: JPY has 0 digits and BHD has 3. Set locale.currencyDigits: "fixed2" for the old behavior. Hash options include display="code", decimals=2 and sign="accounting". Number helpers also accept locale, minDecimals, maxDecimals, grouping, signDisplay, currencyDisplay, unit and unitDisplay where applicable.

Dates and times

{{formatDate issued "EEE dd MMM yyyy HH:mm"}} uses a strict LDML subset. Supported tokens are yyyy yy y M MM MMM MMMM MMMMM d dd E EEE EEEE H HH h hh m mm s ss S SS SSS a Q QQQ X XXX z zzzz. Quote literal text with single quotes; use two apostrophes for one literal apostrophe. YYYY and DD are invalid: use yyyy and dd.

Presets: short, medium, long, full, iso, datetime, time. date retains its old medium fallback on invalid patterns; formatDate reports an expression error. time defaults to a short time. relativeDate accepts a base= value; duration accepts seconds (or unit="ms", "m", "h") and style="clock", "short", or "long".

Input Meaning Zone used
Date, epoch milliseconds, ISO with Z or offset Instant Effective time zone
2026-03-01 Calendar date UTC, so the day never shifts
2026-03-01T09:00 Floating local time Fields as supplied
Other strings Legacy Date parsing Effective time zone

With America/New_York, 2026-03-01T03:00:00Z prints 28 Feb at 22:00; 2026-03-01 remains 1 Mar and a floating 09:00 remains 09:00. An omitted zone uses the host zone. Pin TZ=UTC for predictable deployments.

Table and pivot formats

Use format: "formatNumber", formatArgs: ["C2", "EUR", {"display":"code"}]. A trailing object becomes helper hash options in every renderer. XLSX keeps N/F/D/P/C/A/E and percent results numeric with a native numFmt; Excel-mappable date patterns become date cells containing the effective wall-clock fields. Compact, bytes and relative formats remain text. Excel applies its own display rounding to raw numeric cells.

Exact arithmetic and rounding

Arithmetic defaults to decimal with 34 significant digits of working precision. sum, avg, min, max, round, and number use it. Public numeric results are JavaScript numbers, with about 15 significant digits of output precision. Numeric strings are accumulated exactly; legacy parseFloat inputs such as "12abc" still contribute 12. Non-finite values are skipped in decimal mode.

numeric.roundingMode accepts halfExpand (Excel ROUND, default), halfEven, halfTrunc, halfCeil, halfFloor, ceil, floor, trunc, expand. {{round amount 2 "halfEven"}} or mode="halfEven" overrides it for one call. Set renderConfig.numeric.arithmetic: "float" to retain legacy float sums, averages and round/number behavior. JEXL field-mapping arithmetic remains float.

For three rows of 1.005, displayed currency rows are $1.01 each. The exact unrounded total formats as $3.02. To reconcile with displayed rows use {{currency (sumRounded items "amount" 2) "USD"}}, which prints $3.03.