9. String Functions
The String library provides strings/ functions for Unicode text. Character counts
and indices count Unicode code points, starting at zero. Substring end indices
are excluded. A combining mark counts separately from the character before it.
Operations do not normalize text unless their documentation says so. Searches
match literal text rather than patterns or regular expressions.
Case conversion and word boundaries recognize Unicode letters and digits. Case conversion is locale independent. Character classification and full case mappings use Unicode 17.0.0, including expanding mappings and the contextual Greek final sigma rule.
Table of Contents
- 9.1. String functions
- 9.1.1. strings/case
- 9.1.2. strings/trim
- 9.1.3. strings/split
- 9.1.4. strings/join
- 9.1.5. strings/replace
- 9.1.6. strings/substring
- 9.1.7. strings/starts-with?
- 9.1.8. strings/ends-with?
- 9.1.9. strings/includes?
- 9.1.10. strings/split-lines
- 9.1.11. strings/index-of
- 9.1.12. strings/last-index-of
- 9.1.13. strings/replace-first
- 9.1.14. strings/blank?
- 9.1.15. String templates
- 9.1.16. strings/escape
- 9.1.17. strings/unescape
- 9.1.18. strings/normalize
- 9.1.19. strings/from-code-points
- 9.2. strings/humanize
9.1. String functions ↑
9.1.1. strings/case ↑
Function(strings/case case value) → string
(strings/case cases value) → string
Converts value with one case selector or a list of selectors. A list applies
the conversions from left to right. An empty list returns the input unchanged.
The selector and input must be strings. Unknown selectors produce an error.
| Selector | Conversion |
|---|---|
upper |
Unicode uppercase |
lower |
Unicode lowercase |
camel |
Words joined in camel case |
pascal |
Words joined in Pascal case |
snake |
Lowercase words joined with underscores |
kebab |
Lowercase words joined with hyphens |
title |
Capitalized words joined with spaces |
screaming-snake |
Uppercase words joined with underscores |
case-fold |
Unicode default full case folding |
Case conversion can change the number of code points: straße becomes
STRASSE with upper. Case folding is for caseless matching. It does not
normalize text or use Turkic-specific mappings.
Naming conversions split words at separators and case transitions. An acronym
followed by a capitalized word is split: HTTPServer contains HTTP and
Server. (strings/case [snake upper] HTTPServer) returns HTTP_SERVER.
(strings/case upper straße) (strings/case lower HELLO) (strings/case camel HTTP_server) (strings/case title hELLO_world) (strings/case case-fold Straße)
STRASSE hello httpServer "Hello World" strasse
(strings/case [snake upper] HTTPServer) (strings/case [upper lower] Straße) (strings/case [] Hello) (strings/case [camel snake] hello_world)
HTTP_SERVER strasse Hello hello_world
9.1.2. strings/trim ↑
Function(strings/trim opts s) → string
(strings/trim opts text s) → string
Returns s with whitespace or text removed from the ends selected by opts.
opts is a map tagged with exactly one of left, right, or both, optionally with repeat, as in {<both repeat>}.
Whitespace trimming removes full Unicode whitespace runs.
Text trimming removes one exact match per end, or repeats with repeat.
Both ends are processed left first.
Empty text leaves s unchanged.
(strings/trim <both> "\t \nalpha beta\r ") (strings/trim <both> hi ) (strings/trim <both> hi ) (strings/trim <both> "") (strings/trim <both> "\t\n") (strings/trim <both> hi) (strings/trim <both> "hi ")
"alpha beta" hi hi "" "" hi hi
(strings/trim <left> ha hahaha) (strings/trim <both> ha hahaha) (strings/trim <both repeat> ha hahaha) (strings/trim <both> aba ababa) (strings/trim <both repeat> aba ababa) (strings/trim <left repeat> ha hahaxhaha) (strings/trim <repeat right> ha hahaxhaha) (strings/trim <both repeat> ha hahaxhahaxhaha) (strings/trim <left repeat> ab aabb) (strings/trim <both> abc abc) (strings/trim <both repeat> abc ab) (strings/trim <both repeat> "" abc) (strings/trim <both repeat> "" "") (strings/trim <both repeat> a "") (strings/trim <both repeat> 🙂 🙂🙂x🙂🙂) (strings/trim <both repeat> é Éxé) (strings/trim <both repeat> é éxé) (strings/trim <both> " " " x ") (strings/trim <both repeat> " " " x ")
haha ha "" ba ba xhaha hahax xhahax aabb "" ab abc "" "" x Éx éxé " x " x
{both-left (strings/trim <both left> abc) both-right (strings/trim <both right> abc) conflicting-sides (strings/trim <left right> abc) extra (strings/trim <both> a abc extra) missing (strings/trim) missing-side (strings/trim {} abc) old-arity (strings/trim abc) opts-list (strings/trim [both] abc) opts-null (strings/trim null abc) opts-string (strings/trim both abc) repeat-only (strings/trim <repeat> abc) source-null (strings/trim <both> null) source-number (strings/trim <left> 1) text-null (strings/trim <left> null abc) text-number (strings/trim <right> 1 abc) text-options (strings/trim <all both> a abc) text-opts-null (strings/trim null a abc) text-source-null (strings/trim <right> a null) text-source-number (strings/trim <both repeat> a 1) unknown-option (strings/trim <all both> abc)}
#cases [{output #err <invalid value> select missing-side} {output #err <invalid value> select repeat-only} {output #err <invalid value> select conflicting-sides} {output #err <invalid value> select both-left} {output #err <invalid value> select both-right} {output #err <invalid value> select unknown-option} {output #err <invalid value> select text-options} {output #err <mismatch type> select opts-string} {output #err <mismatch type> select opts-list} {output #err <mismatch type> select opts-null} {output #err <mismatch type> select text-opts-null} {output #err <mismatch type> select source-null} {output #err <mismatch type> select source-number} {output #err <mismatch type> select text-source-null} {output #err <mismatch type> select text-source-number} {output #err <mismatch type> select text-null} {output #err <mismatch type> select text-number} {output #err <arity mismatch> select missing} {output #err <arity mismatch> select old-arity} {output #err <arity mismatch> select extra}]
9.1.3. strings/split ↑
Function(strings/split string separator) → list
(strings/split string separator limit) → list
Splits at each literal occurrence of separator, preserving empty fields.
An empty separator splits into Unicode code points; splitting an empty string
with an empty separator returns a list containing the empty string.
An optional positive limit permits at most that many parts and keeps the
unsplit remainder in the final part. A zero limit removes trailing empty
parts. A negative limit preserves all parts, including trailing empty strings.
Omitting limit preserves trailing empty parts.
(strings/split "a,b,c" ",") (strings/split é猫🙂 "") (strings/split a.b. ".") (strings/split "" ",") (strings/split "" "")
[[a b c] [é 猫 🙂] [a b ""] [""] []]
9.1.4. strings/join ↑
Function(strings/join strings separator) → string
Joins a list of strings with separator between consecutive elements.
An empty list produces the empty string. Elements and the separator must be strings.
9.1.5. strings/replace ↑
Function(strings/replace string search replacement) → string
Replaces non-overlapping literal occurrences of search, from left to right.
An empty search inserts replacement before, between, and after the input's
Unicode code points: (strings/replace ab "" x) returns xaxbx.
(strings/replace banana na x) (strings/replace ab "" x) (strings/replace é猫 "" 🙂) (strings/replace a.b. "." 猫)
baxx xaxbx 🙂é🙂猫🙂 a猫b猫
9.1.6. strings/substring ↑
Function(strings/substring string start) → string
(strings/substring string start end) → string
Returns the code points from start up to, but excluding, end.
Without end, returns the rest of the string. Both indices must be integers
between zero and the string length, and start must not exceed end. Other
indices produce #err <bounds index>.
(strings/substring Aé猫Z 1 3) (strings/substring é猫🙂 1 3) (strings/substring é猫 2 2) (strings/substring é猫🙂 1)
é猫 猫🙂 "" 猫🙂
9.1.7. strings/starts-with? ↑
Function(strings/starts-with? string prefix) → boolean
Returns whether the string begins with the literal prefix.
Every string starts with the empty string.
(strings/starts-with? abc a) (strings/starts-with? é猫 é) (strings/starts-with? é猫 猫) (strings/starts-with? é猫 "")
true true false true
9.1.8. strings/ends-with? ↑
Function(strings/ends-with? string suffix) → boolean
Returns whether the string ends with the literal suffix.
Every string ends with the empty string.
(strings/ends-with? abc c) (strings/ends-with? é猫 猫) (strings/ends-with? é猫 é) (strings/ends-with? é猫 "")
true true false true
9.1.9. strings/includes? ↑
Function(strings/includes? string search) → boolean
Returns whether the string contains the literal search.
Every string includes the empty string.
(strings/includes? a.b ".") (strings/includes? é猫🙂 猫) (strings/includes? é猫 z) (strings/includes? é猫 "") (strings/includes? é é)
true true false true false
9.1.10. strings/split-lines ↑
Function(strings/split-lines s) → list
Returns the lines of s separated by LF or CRLF, without their line endings.
Trailing empty lines are omitted. A lone CR is ordinary content. An empty string produces a list containing one empty string. A nonempty string containing only line endings produces an empty list.
[(strings/split-lines "a\nb\r\nc\n") (strings/split-lines "") (strings/split-lines "\n\r\n") (strings/split-lines "a\rb") (strings/split-lines "a\n\nb") (strings/split-lines "a b")]
(strings/split-lines """ a b\r c """ ) (strings/split-lines "") (strings/split-lines """ \r """ ) (strings/split-lines "a\rb") (strings/split-lines """ a b """ ) (strings/split-lines a b)
[[a b c] [""] [] [ "a\rb"] [a "" b] [a b]]
9.1.11. strings/index-of ↑
Function(strings/index-of s value) → integer or null
(strings/index-of s value start) → integer or null
Returns the first index of the string value in s at or after start, or null if not found.
The integer start defaults to zero.
Negative starts are treated as zero.
A start beyond the string length finds no nonempty value.
An empty value matches at the start clamped to the range from zero through the string length.
Indices are not narrowed to a host's smaller integer type.
[(strings/index-of banana ana) (strings/index-of banana ana 2) (strings/index-of banana ana -3) (strings/index-of banana ana 9) (strings/index-of "🙂a🙂b" b) (strings/index-of "é" "é") (strings/index-of ABC a) (strings/index-of abc "" 99) (strings/index-of abc "" -9) (strings/index-of "" "") (strings/index-of abc b 9223372036854775807) (strings/index-of abc "" 9223372036854775807)]
(strings/index-of banana ana) (strings/index-of banana ana 2) (strings/index-of banana ana -3) (strings/index-of banana ana 9) (strings/index-of 🙂a🙂b b) (strings/index-of é é) (strings/index-of ABC a) (strings/index-of abc "" 99) (strings/index-of abc "" -9) (strings/index-of "" "") (strings/index-of abc b 9223372036854775807) (strings/index-of abc "" 9223372036854775807)
1 3 1 null 3 null null 3 0 0 null 3
9.1.12. strings/last-index-of ↑
Function(strings/last-index-of s value) → integer or null
(strings/last-index-of s value start) → integer or null
Returns the last index of the string value in s at or before start, or null if not found.
The integer start defaults to the string length.
Starts beyond the string length are treated as the string length.
A negative start returns null, including when value is empty.
An empty value matches at any index from zero through the string length.
The start limits the beginning of a match, not its end.
Indices are not narrowed to a host's smaller integer type.
[(strings/last-index-of banana ana) (strings/last-index-of banana ana 2) (strings/last-index-of banana ana -1) (strings/last-index-of banana ana 9223372036854775807) (strings/last-index-of abc abc 1) (strings/last-index-of abc "") (strings/last-index-of abc "" -1) (strings/last-index-of abc "" 99) (strings/last-index-of "🙂a🙂b" "🙂") (strings/last-index-of "é" "é") (strings/last-index-of "" "")]
(strings/last-index-of banana ana) (strings/last-index-of banana ana 2) (strings/last-index-of banana ana -1) (strings/last-index-of banana ana 9223372036854775807) (strings/last-index-of abc abc 1) (strings/last-index-of abc "") (strings/last-index-of abc "" -1) (strings/last-index-of abc "" 99) (strings/last-index-of 🙂a🙂b 🙂) (strings/last-index-of é é) (strings/last-index-of "" "")
3 1 null 3 0 3 null 3 2 null 0
9.1.13. strings/replace-first ↑
Function(strings/replace-first s match replacement) → string
Returns s with the first occurrence of match replaced by replacement.
Both match and replacement are literal strings.
An empty match inserts replacement at the start.
Returns s unchanged when there is no match.
[(strings/replace-first abab ab X) (strings/replace-first aaa aa X) (strings/replace-first "a.b.a" "." "$1") (strings/replace-first ab "" "-") (strings/replace-first "🙂x" "" "-") (strings/replace-first "" "" "+") (strings/replace-first abc x q) (strings/replace-first a a aa) (strings/replace-first "$1" "$1" "\\")]
(strings/replace-first abab ab X) (strings/replace-first aaa aa X) (strings/replace-first a.b.a "." $1) (strings/replace-first ab "" -) (strings/replace-first 🙂x "" -) (strings/replace-first "" "" +) (strings/replace-first abc x q) (strings/replace-first a a aa) (strings/replace-first $1 $1 "\\")
Xab Xa a$1b.a -ab -🙂x + abc aa "\\"
9.1.14. strings/blank? ↑
Function(strings/blank? s) → boolean
Returns true if s is null, empty, or contains only whitespace, otherwise false.
Other non-string values produce #err <mismatch type>.
[(strings/blank? null) (strings/blank? "") (strings/blank? " \t\r\n") (strings/blank? " ") (strings/blank? " ") (strings/blank? " ") (strings/blank? " ") (strings/blank? "") (strings/blank? " a ")]
(strings/blank? null) (strings/blank? "") (strings/blank? " \t\r\n") (strings/blank? ) (strings/blank? ) (strings/blank? ) (strings/blank? ) (strings/blank? ) (strings/blank? " a ")
true true true true true true true false false
9.1.15. String templates ↑
A template retains literal strings and evaluated values. It is accepted as a
string by string operations; template? distinguishes it from an
ordinary string. Rendering joins the literal pieces with the string forms of
the values.
(let [name Ada]
(templates/parts ~"hello-,.name"))
; => {strings [hello- ""] values [Ada]}
(let [name Ada]
(template? ~"hello-,.name"))
; => true
(let [name Ada]
~"hello-,.name")
; => hello-Ada
(let [name Ada]
(str hello- .name))
; => hello-Ada
Use the template to embed forms in a string. Use str to concatenate values.
(let [name Ada] [(= ~"hello-,.name" (str hello- .name)) (template? ~"hello-,.name") (template? (str hello- .name))])
true true false
templates/from-parts constructs a template from a map with strings
and values lists. The strings list must have one more item than values.
(templates/from-parts {strings [hello- ""] values [Ada]})
; => hello-Ada
templates/render renders a template. Its optional escape function
receives each evaluated embedded value before it is rendered; literal pieces
pass through unchanged.
For example, escape a query value without escaping its literal parameter prefix:
(let [term "cats & dogs"]
(templates/render
~"search=,.term"
{escape (strings/escape url-query-value)}))
; => "search=cats%20%26%20dogs"
Use the corresponding unescape function to decode an escaped string.
Passing a template to str or strings/join renders its evaluated values.
The result is an ordinary string.
Map literal keys are strings and are not evaluated. To create a key from a template, pass it as a value to a map operation:
(let [name Ada]
(put {} ~"hello-,.name" 1))
; => {hello-Ada 1}
9.1.16. strings/escape ↑
Function(strings/escape mode text) → string
(strings/escape mode) → function
Escapes text for the specified mode. With only a mode, returns a unary function
that escapes its argument, for use as a template's escape option. The function
prints and hashes as its call, such as (strings/escape html-text), and
renders a template argument before escaping it.
(strings/escape json-pointer "a/b~") ; => a~1b~0
(strings/escape url-query-value "a&b c") ; => a%26b%20c
(strings/escape url-form-field "a&b c") ; => a%26b+c
(strings/escape csv "a,b") ; => "\"a,b\""
(let [escape-html (strings/escape html-text)]
(.escape-html "<Alice>")) ; => "<Alice>"
Modes are json, dust, ron, csv, json-pointer, html-text,
html-attribute, url-path-segment, url-query-value, and url-form-field.
JSON Pointer mode escapes one segment; URL modes escape one component; CSV mode
escapes one field. The json, dust, and ron modes escape the contents of
a double-quoted string without adding quotes. HTML attribute mode also escapes
quotation marks. URL form fields encode spaces as +; the other URL modes use
%20. An unknown mode produces #err <invalid value>.
[(strings/escape html-attribute "&<>\"'")
(strings/escape html-attribute "<b>Tom & 'Sue'</b>")
(strings/escape html-attribute "&")
(strings/escape html-attribute "\\$1🙂")
(strings/escape html-attribute "")]
(strings/escape html-attribute &<>"')
(strings/escape html-attribute "<b>Tom & 'Sue'</b>")
(strings/escape html-attribute &)
(strings/escape html-attribute "\\$1🙂")
(strings/escape html-attribute "")
&<>"'
"<b>Tom & 'Sue'</b>"
&amp;
"\\$1🙂"
""
(strings/escape json-pointer "a/b~")
(strings/unescape json-pointer "a~1b~0")
(strings/escape url-query-value "a&b c")
(strings/escape url-form-field "a&b c")
(strings/unescape url-form-field "a%26b+c")
(strings/escape csv "a,b")
(strings/unescape csv "\"a,b\"")
(strings/escape url-form-field "*~ ")
(strings/escape json-pointer a/b~)
(strings/unescape json-pointer a~1b~0)
(strings/escape url-query-value "a&b c")
(strings/escape url-form-field "a&b c")
(strings/unescape url-form-field a%26b+c)
(strings/escape csv "a,b")
(strings/unescape
csv
"""
"a,b"
"""
)
(strings/escape url-form-field "*~ ")
a~1b~0
a/b~
a%26b%20c
a%26b+c
"a&b c"
"""
"a,b"
"""
"a,b"
*%7E+
(strings/escape json "a\"b\n")
(strings/unescape json "\\uD83D\\uDE00")
(strings/unescape ron (strings/escape ron "a\"b\n"))
(strings/unescape dust (strings/escape dust "a\\b"))
(strings/unescape json "\\q")
(strings/unescape url-query-value "%2G")
(strings/unescape json-pointer "~2")
(strings/escape
json
"""
a"b
"""
)
(strings/unescape json "\\uD83D\\uDE00")
(strings/unescape
ron
(strings/escape
ron
"""
a"b
"""
))
(strings/unescape dust (strings/escape dust a\b))
(strings/unescape json "\\q")
(strings/unescape url-query-value %2G)
(strings/unescape json-pointer "~2")
""a\u005c"b\\n""
😀
"""
a"b
"""
a\b
#err {<invalid value>
message "invalid string escape"}
#err {<invalid value>
message "invalid URL percent escape"}
#err {<invalid value>
message "invalid JSON Pointer escape"}
(strings/escape html-text "<a & b>")
(strings/escape html-attribute "\"<a>\"")
(strings/unescape html-text "<a & b>")
(strings/unescape html-attribute "😀 "x"")
(strings/unescape html-text "© ≂̸")
(strings/escape html-text "<a & b>")
(strings/escape
html-attribute
"""
"<a>"
"""
)
(strings/unescape html-text "<a & b>")
(strings/unescape html-attribute "😀 "x"")
(strings/unescape html-text "© ≂̸")
"<a & b>"
"<a>"
"<a & b>"
""😀 "x"""
"© ≂̸"
(strings/escape url-path-segment "a/b")
(strings/unescape url-path-segment a%2Fb)
(let [escape-html (strings/escape html-text)] (.escape-html "<Alice>"))
(let [decode (strings/unescape html-text)] (.decode "<Alice>"))
(let [name "<Alice>"] (templates/render ~"<p>,.name,</p>" {escape (strings/escape html-text)}))
(fn? (strings/escape html-text))
(strings/escape unknown x)
(strings/unescape unknown x)
(strings/escape 1 x)
(strings/escape html-text 1)
((strings/escape html-text) x y)
(strings/escape url-path-segment a/b)
(strings/unescape url-path-segment a%2Fb)
(let [escape-html (strings/escape html-text)] (.escape-html "<Alice>"))
(let [decode (strings/unescape html-text)] (.decode <Alice>))
(let [name "<Alice>"] (templates/render ~"<p>,.name,</p>" {escape (strings/escape html-text)}))
(fn? (strings/escape html-text))
(strings/escape unknown x)
(strings/unescape unknown x)
(strings/escape 1 x)
(strings/escape html-text 1)
((strings/escape html-text) x y)
a%2Fb
a/b
<Alice>
"<Alice>"
"<p><Alice></p>"
true
#err <invalid value>
#err <invalid value>
#err <mismatch type>
#err <mismatch type>
#err <arity mismatch>
(let [escape-html (strings/escape html-text)]
[(.escape-html "<Alice>")
(fn? .escape-html)
(.escape-html ~"<,(str b),>")
(hash/digest sha256 .escape-html)])
(let
[escape-html (strings/escape html-text)]
[(.escape-html "<Alice>") (fn? .escape-html)
(.escape-html ~"<,(str b),>") (hash/digest sha256 .escape-html)])
<Alice>
true
<b>
#hash #sha256 2d140a5655b694b51aecece118441a80fdd245852dc87ae6babb33de709aba34
[(strings/escape)
(strings/unescape html-text a b)
((strings/escape html-text))
((strings/unescape html-text) 1)]
(strings/escape)
(strings/unescape html-text a b)
((strings/escape html-text))
((strings/unescape html-text) 1)
#err <arity mismatch>
#err <arity mismatch>
#err <arity mismatch>
#err <mismatch type>
9.1.17. strings/unescape ↑
Function(strings/unescape mode text) → string
(strings/unescape mode) → function
Decodes text for the same modes as strings/escape. With only a mode, returns
a unary decoding function that prints and hashes as its call, such as
(strings/unescape url-query-value). Invalid JSON Pointer, URL percent, CSV, and quoted
string escapes produce #err <invalid value>, as do URL percent escapes whose
bytes are not UTF-8, since strings are always Unicode text. HTML decoding recognizes
semicolon-terminated named and numeric character references.
(strings/unescape json-pointer a~1b~0) ; => a/b~
(strings/unescape html-text "<Alice>") ; => "<Alice>"
(let [decode (strings/unescape url-query-value)]
(.decode cats%20%26%20dogs)) ; => "cats & dogs"
9.1.18. strings/normalize ↑
Function(strings/normalize s) → string
(strings/normalize s form) → string
Returns s normalized to the Unicode normalization form, defaulting to NFC.
The form is one of the exact strings NFC, NFD, NFKC, or NFKD.
Other strings produce an error.
NFC and NFD apply canonical normalization.
NFKC and NFKD also apply compatibility normalization, which can remove meaningful distinctions.
Normalization does not perform case folding or guarantee visually distinct identifiers.
[(strings/normalize "é") (strings/normalize "é" NFD) (strings/normalize "A①ffi" NFKC) (strings/normalize "Å①" NFKD) (strings/normalize "①" NFC) (strings/normalize "가" NFC) (strings/normalize "" NFD) (strings/normalize "É" NFC) (strings/normalize "ࢡ" NFC)]
(strings/normalize é) (strings/normalize é NFD) (strings/normalize A①ffi NFKC) (strings/normalize Å① NFKD) (strings/normalize ① NFC) (strings/normalize 가 NFC) (strings/normalize "" NFD) (strings/normalize É NFC) (strings/normalize ࢡ NFC)
é é A1ffi Å1 ① 가 "" É ࢡ
(strings/normalize "é" nfc)
(strings/normalize é nfc)
#err <form invalid normalization>
9.1.19. strings/from-code-points ↑
Function(strings/from-code-points points) → string
Returns the string formed by the Unicode scalar values in the list points, in order.
Each element must be an integer from zero through 1114111, excluding the surrogate range 55296 through 57343. Invalid scalar values and non-integer elements produce errors. An empty list produces the empty string. Unassigned code points and noncharacters are accepted when they are valid scalar values. The result is not normalized.
[(strings/from-code-points [65 769]) (strings/from-code-points [128578]) (strings/from-code-points []) (strings/from-code-points [0 65]) (strings/from-code-points [1114111]) (strings/from-code-points [888])]
(strings/from-code-points [65 769]) (strings/from-code-points [128578]) (strings/from-code-points []) (strings/from-code-points [0 65]) (strings/from-code-points [1114111]) (strings/from-code-points [888])
Á 🙂 "" "\u0000A"
9.2. strings/humanize ↑
Function(strings/humanize value options?) → string
Formats an integer, float, duration, or UTC value as readable text. Options are a map with string keys. Unknown options and options irrelevant to the value's kind are errors.
| Value kind | Options | Defaults |
|---|---|---|
| Integer or float | scale, unit, precision |
SI scale, empty unit, precision 1 |
| Duration | precision |
Precision 1 |
| UTC | mode, now |
Absolute mode |
For numbers, scale is si or binary. SI uses powers of 1000 with prefixes
such as k and M; binary uses powers of 1024 with prefixes such as Ki and
Mi. A string unit is appended directly, allowing B, /s, and Unicode
units. Signed integers retain full precision before rounding.
precision is an integer from zero through nine and selects the maximum
fractional decimal places. Rounding is halfway away from zero; trailing
fractional zeros are omitted. A rounded value can carry into the next unit:
999950 at the default precision becomes 1M.
(strings/humanize 1500) (strings/humanize 1536 {scale binary unit B}) (strings/humanize 1234 {precision 2 unit "/s"}) (strings/humanize -1250) (strings/humanize 999950) (strings/humanize 9223372036854775807 {precision 9})
1.5k 1.5KiB 1.23k/s -1.3k 1M 9.223372037E
Durations use hours, minutes, seconds, or a suitable subsecond unit. Examples
include 1h 30m, 2.5s, 150µs, and 100ns. The precision applies to the
displayed fractional unit; the stored tick value is unchanged.
(strings/humanize #dur PT1H30M) (strings/humanize #dur PT2.5S) (strings/humanize #dur PT0.00015S) (strings/humanize #dur PT59.99S) (strings/humanize #dur PT1.2345678S {precision 9}) (strings/humanize #dur PT0.0000001S)
"1h 30m" 2.5s 150µs 1m 1.2345678s 100ns
UTC mode is absolute or relative. Absolute formatting produces the
canonical UTC timestamp, retaining its 100 ns precision. Relative formatting
requires an explicit UTC now option and produces text such as 3 minutes ago
or in 2 days. It selects the largest whole unit among days, hours, minutes,
and seconds; differences shorter than a second produce now. Supplying now
in absolute mode is an error. The function never reads the clock implicitly.
(strings/humanize #utc 2026-10-29T12:00:00.1234567Z) (strings/humanize #utc 2026-10-29T12:00Z {mode relative now #utc 2026-10-29T12:03Z}) (strings/humanize #utc 2026-10-31T12:00Z {mode relative now #utc 2026-10-29T12:00Z}) (strings/humanize #utc 2026-10-29T12:00Z {mode relative now #utc 2026-10-29T12:00Z})
(strings/humanize #utc 2026-10-29T12:00:00.1234567Z) (strings/humanize #utc 2026-10-29T12:00:00Z {mode relative now #utc 2026-10-29T12:03:00Z}) (strings/humanize #utc 2026-10-31T12:00:00Z {mode relative now #utc 2026-10-29T12:00:00Z}) (strings/humanize #utc 2026-10-29T12:00:00Z {mode relative now #utc 2026-10-29T12:00:00Z})
2026-10-29T12:00:00.1234567Z "3 minutes ago" "in 2 days" now
(strings/humanize #utc 2026-10-29T12:00Z {mode relative})
(strings/humanize #utc 2026-10-29T12:00:00Z {mode relative})
#err <invalid value>
See the Time library for temporal constructors, arithmetic,
calendar operations, and time/now.