Docs / Reference
a9script authoring pack — date & time functions
The date & time functions, with their arguments and a line of real script each. Called by bare name; nothing is imported. A call marked pauses does real work outside the script: the run is saved, and continues on the next line with the result.
This is one part of the authoring pack — how a script is executed at all is the model part, and the other groups of functions are parts of their own. All of them are named at the end.
Generated — do not edit. Every block of script below is executed by the platform’s own test suite, and every error message is the one the platform produces today, so none of this can be what was true when someone last wrote it down.
formatDate(date, pattern) — immediate
Writes a date out in a pattern of your own, always in UTC. The tokens are YYYY, MM, DD, HH, mm and ss; every other character of the pattern is written as it stands.
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value fromnew Date(...). A datetime without a timezone is refused: it would mean a different moment on every machine that read it.pattern(string) — The shape of the answer, e.g.DD.MM.YYYYorYYYY-MM-DD HH:mm:ss. Keep punctuation between the tokens: a word that happens to spell one carries it.
Answers: The formatted text.
log(formatDate(input.event.receivedAt, "YYYY-MM-DD HH:mm"));
addDays(date, days) — immediate
Moves a date forwards or backwards by whole days and answers the new moment, in UTC. The time of day is kept.
date(string | number | date) — An ISO date, a datetime that carries its timezone, milliseconds since 1970, or a date value — the same datesformatDatetakes.days(number) — How many days to move. A negative count moves back.
Answers: The moved date as an ISO string, e.g. 2026-07-21T00:00:00.000Z.
const due = addDays(input.event.receivedAt, 14);
log("payable by " + formatDate(due, "YYYY-MM-DD"));
dateDiff(from, to) — immediate
How many whole days lie between two dates, counted as UTC calendar days: positive when to is the later one, negative when it is the earlier.
from(string | number | date) — The date to count from — an ISO date, milliseconds since 1970, or a date value.to(string | number | date) — The date to count to, in any of the same forms.
Answers: The number of days. Two moments on the same UTC day answer 0; two hours either side of midnight answer 1, because the question is which day each one falls on.
const age = dateDiff("2026-03-01", input.event.receivedAt);
log("the order is " + age + " days old");
now() — pauses
The current moment, in milliseconds. The same clock Date.now() reads, so the two can never disagree — and the reading is kept: a run that is saved and continued later still sees the moment it read.
Answers: Milliseconds since the start of 1970, as a number.
const startedAt = now();
log("started at " + formatDate(startedAt, "YYYY-MM-DD HH:mm:ss"));
today() — pauses
Today’s date in UTC. The day now() falls on, written out.
Answers: The date as YYYY-MM-DD.
log("the report covers " + today());
dateAdd(date, amount, unit, timeZone?) — pauses
Moves a moment forwards by whole units and answers the new moment. Months and years follow the calendar: one month after 31 January is 28 February, because there is no 31 February.
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.amount(number) — How many units to move. A whole number; a negative one moves backwards.unit(string) — Which unit to move by:year,month,week,day,hour,minute,secondormillisecond— plurals work too.timeZone(string, optional) — Whose calendar to walk, such asEurope/Berlin. Without it, UTC — where a day is always twenty-four hours. With it, a day is a day on that clock: 09:00 in Berlin plus one day is 09:00 the next morning even when the clocks moved overnight, while plus 24 hours is 10:00.
Answers: The new moment as ISO text, written in the timezone that was named — 2026-02-28T10:00:00.000Z when none was.
const due = dateAdd(input.event.receivedAt, 1, "month");
log("payable by " + dateFormat(due, "DD.MM.YYYY"));
const sameTimeTomorrow = dateAdd(input.event.receivedAt, 1, "day", "Europe/Berlin");
log("and again at " + dateFormat(sameTimeTomorrow, "HH:mm", "Europe/Berlin"));
dateSubtract(date, amount, unit, timeZone?) — pauses
Moves a moment backwards by whole units — dateAdd the other way. Note that the two do not always undo each other: one month after 31 January is 28 February, and one month before that is 28 January.
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.amount(number) — How many units to move back. A whole number.unit(string) — Which unit to move by:year,month,week,day,hour,minute,secondormillisecond— plurals work too.timeZone(string, optional) — Whose calendar to walk, such asEurope/Berlin. Without it, UTC — where a day is always twenty-four hours. With it, a day is a day on that clock: 09:00 in Berlin plus one day is 09:00 the next morning even when the clocks moved overnight, while plus 24 hours is 10:00.
Answers: The new moment as ISO text, written in the timezone that was named.
const since = dateSubtract(today(), 7, "days");
log("looking back to " + since);
dateDifference(from, to, unit, timeZone?) — pauses
How many WHOLE units lie between two moments, counted the same way dateAdd moves them — so adding the answer to from never passes to.
from(string | number | date) — The moment to count from. An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.to(string | number | date) — The moment to count to, in any of the same forms.unit(string) — Which unit to count in:year,month,week,day,hour,minute,secondormillisecond— plurals work too.timeZone(string, optional) — Whose calendar to walk, such asEurope/Berlin. Without it, UTC — where a day is always twenty-four hours. With it, a day is a day on that clock: 09:00 in Berlin plus one day is 09:00 the next morning even when the clocks moved overnight, while plus 24 hours is 10:00.
Answers: The number of whole units, positive when to is the later moment and negative when it is the earlier one. Anything short of a whole unit is dropped: two moments twenty-three hours apart are 0 days apart. One thing to know about leap days: 29 February to 28 February the next year is 0 years, because the anniversary is 1 March. For calendar days — which day each moment falls on, rather than how much time passed — use dateDiff.
const age = dateDifference(input.event.receivedAt, now(), "day");
log("the order is " + age + " days old");
dateIsBefore(date, other, unit?, timeZone?) — pauses
Is the first moment earlier than the second?
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.other(string | number | date) — The moment to compare against.unit(string, optional) — Compare at this granularity instead of to the millisecond —"day"asks whether the first falls on an earlier day, so two moments on one day answer false. One ofyear,month,week,day,hour,minute,secondormillisecond— plurals work too.timeZone(string, optional) — Whose day (or week, or month) it is — 23:30 UTC is already the next day in Tokyo. Only meaningful together with a unit, and refused without one. Defaults to UTC.
Answers: true or false.
if (dateIsBefore(input.event.receivedAt, today())) {
log("this one arrived before today");
}
dateIsAfter(date, other, unit?, timeZone?) — pauses
Is the first moment later than the second?
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.other(string | number | date) — The moment to compare against.unit(string, optional) — Compare at this granularity instead of to the millisecond. One ofyear,month,week,day,hour,minute,secondormillisecond— plurals work too.timeZone(string, optional) — Whose day (or week, or month) it is — 23:30 UTC is already the next day in Tokyo. Only meaningful together with a unit, and refused without one. Defaults to UTC.
Answers: true or false.
log(dateIsAfter("2026-07-14", "2026-07-13"));
dateIsEqual(date, other, unit?, timeZone?) — pauses
Are the two the same moment? With a unit, whether they fall in the same one — which is how to ask “were these on the same day” without comparing text.
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.other(string | number | date) — The moment to compare against.unit(string, optional) — Compare at this granularity:"day"answers true for any two moments on the same day — whose day it is depends on the timezone. One ofyear,month,week,day,hour,minute,secondormillisecond— plurals work too.timeZone(string, optional) — Whose day (or week, or month) it is — 23:30 UTC is already the next day in Tokyo. Only meaningful together with a unit, and refused without one. Defaults to UTC.
Answers: true or false.
if (dateIsEqual(input.event.receivedAt, now(), "day")) {
log("it arrived today");
}
dateIsBetween(date, start, end) — pauses
Is the moment inside the window? Both edges count as inside, so a window built from dateStartOf and dateEndOf holds every moment of the period and no more.
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.start(string | number | date) — The first moment of the window.end(string | number | date) — The last moment of the window.
Answers: true or false. A window whose start is after its end is refused rather than answering false for everything, which would look exactly like an empty window.
const from = dateStartOf(today(), "month");
const to = dateEndOf(today(), "month");
log(dateIsBetween(input.event.receivedAt, from, to));
dateStartOf(date, unit, timeZone?) — pauses
The first moment of the day, month, year or other unit the date falls in. A week starts on Monday.
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.unit(string) — Which period:year,month,week,day,hour,minute,secondormillisecond— plurals work too.timeZone(string, optional) — A timezone name such asEurope/Vienna, orUTC. Defaults to UTC — never the machine’s own, so the same script answers the same everywhere. A name nobody has is refused rather than quietly read as UTC.
Answers: The moment as ISO text, written in the timezone that was asked for. On a day whose clocks moved, this is that day’s real first moment — 2026-03-29T00:00:00.000+01:00 in Vienna, even though the day ends on +02:00.
const monthStart = dateStartOf(now(), "month", "Europe/Vienna");
log("the month began at " + monthStart);
dateEndOf(date, unit, timeZone?) — pauses
The LAST millisecond of the day, month, year or other unit the date falls in.
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.unit(string) — Which period:year,month,week,day,hour,minute,secondormillisecond— plurals work too.timeZone(string, optional) — A timezone name such asEurope/Vienna, orUTC. Defaults to UTC — never the machine’s own, so the same script answers the same everywhere. A name nobody has is refused rather than quietly read as UTC.
Answers: The moment as ISO text in the timezone that was asked for, e.g. 2026-02-28T23:59:59.999Z — the last millisecond, so dateIsBetween with it covers the whole period.
const monthEnd = dateEndOf(now(), "month");
log("the month runs until " + monthEnd);
dateParse(text, pattern, timeZone?) — pauses
Reads a date somebody else wrote, by the pattern it was written in — the way to take 14.07.2026 from a file or a form and turn it into a moment.
text(string) — The text to read. It must match the pattern exactly, with nothing left over.pattern(string) — The shape the text is in, from the number tokensYYYY,MM,DD,HH,mm,ssandSSS; everything else in the pattern must appear in the text as it stands. What the pattern does not name starts the period, soYYYY-MMreads as the first of that month at midnight, and a pattern that names no part of a date at all is refused rather than answering 1970. Month names and two-digit years can be written but not read — a name needs a language and26cannot say which century it means.timeZone(string, optional) — Which timezone the text is written in —2026-07-14 12:30means a different moment in Vienna than in UTC. Defaults to UTC. A wall clock that never happened, because the clocks jumped over it, answers the moment the day reached it; one that happened twice answers the first of them.
Answers: The moment as ISO text, written in the timezone it was read in.
const paidAt = dateParse("14.07.2026", "DD.MM.YYYY", "Europe/Vienna");
log("paid at " + paidAt);
dateFormat(date, pattern, timeZone?, locale?) — pauses
Writes a moment out in a pattern of your own, in the timezone you name — the same tokens formatDate uses, plus milliseconds and the names of months and days.
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.pattern(string) — The shape of the answer.YYYYandYYfor the year,MMfor the month andMMM/MMMMfor its name,DDfor the day andDDD/DDDDfor the weekday’s name,HH,mm,ssandSSSfor the time. Every other character is written as it stands.timeZone(string, optional) — A timezone name such asEurope/Vienna, orUTC. Defaults to UTC — never the machine’s own, so the same script answers the same everywhere. A name nobody has is refused rather than quietly read as UTC.locale(string, optional) — Which language the month and weekday names are written in — a language tag such asde-DE. Defaults toen-US, stated rather than taken from the machine, so the same script writes the same date everywhere. A tag nobody has data for is refused rather than quietly written in English.
Answers: The written text.
log(dateFormat(now(), "DDDD, DD. MMMM YYYY", "Europe/Vienna", "de-DE"));
dateGet(date, unit, timeZone?) — pauses
Reads one part of a date as a number — the year, the month, the day, the time, or which day of the week it is.
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.unit(string) — Which part:year,month(1–12),day,hour,minute,second,millisecond, orweekday(1 for Monday through 7 for Sunday).timeZone(string, optional) — A timezone name such asEurope/Vienna, orUTC. Defaults to UTC — never the machine’s own, so the same script answers the same everywhere. A name nobody has is refused rather than quietly read as UTC.
Answers: The part as a number. Which one it is depends on the timezone: 23:30 UTC is already the next day, with a different weekday, in Vienna.
if (dateGet(now(), "weekday", "Europe/Vienna") === 1) {
log("it is Monday in Vienna");
}
dateSet(date, unit, value, timeZone?) — pauses
Answers the same moment with one part changed — the way to say “nine o’clock that morning” or “the first of that month”.
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.unit(string) — Which part to change:year,month,day,hour,minute,secondormillisecond. The weekday cannot be set — move the date withdateAddinstead.value(number) — What to set it to. A value the part cannot hold is refused by name — the 31st of a month with 30 days says so, rather than quietly becoming the 1st of the next one. Changing the MONTH to a shorter one pulls the day back to its last day, exactly asdateAdddoes.timeZone(string, optional) — A timezone name such asEurope/Vienna, orUTC. Defaults to UTC — never the machine’s own, so the same script answers the same everywhere. A name nobody has is refused rather than quietly read as UTC.
Answers: The new moment as ISO text, written in the timezone that was asked for.
const nine = dateSet(dateStartOf(now(), "day", "Europe/Vienna"), "hour", 9, "Europe/Vienna");
log("the reminder goes out at " + nine);
isWeekend(date, timeZone?) — pauses
Is the date a Saturday or a Sunday?
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.timeZone(string, optional) — A timezone name such asEurope/Vienna, orUTC. Defaults to UTC — never the machine’s own, so the same script answers the same everywhere. A name nobody has is refused rather than quietly read as UTC.
Answers: true or false. In the timezone asked for: Friday evening in UTC is already Saturday in Tokyo.
if (isWeekend(now(), "Europe/Vienna")) {
log("holding this until Monday");
}
isLeapYear(date, timeZone?) — pauses
Does the year this date falls in have a 29 February?
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.timeZone(string, optional) — A timezone name such asEurope/Vienna, orUTC. Defaults to UTC — never the machine’s own, so the same script answers the same everywhere. A name nobody has is refused rather than quietly read as UTC.
Answers: true or false, by the full rule — 2000 was a leap year, 1900 was not. Which year the date falls in depends on the timezone: 23:30 UTC on New Year’s Eve is already the new year further east.
log(isLeapYear("2024-05-05"));
daysInMonth(date, timeZone?) — pauses
How many days the month this date falls in has.
date(string | number | date) — An ISO date (2026-07-14), a datetime that carries its timezone (2026-07-14T12:30:00Z), milliseconds since 1970, or a date value. A datetime without a timezone is refused: it would mean a different moment on every machine that read it.timeZone(string, optional) — A timezone name such asEurope/Vienna, orUTC. Defaults to UTC — never the machine’s own, so the same script answers the same everywhere. A name nobody has is refused rather than quietly read as UTC.
Answers: The number of days — 28, 29, 30 or 31.
const days = daysInMonth(now());
log("this month has " + days + " days");
The rest of this pack
The page above is everything that is true only HERE. Ask for these parts by name for the rest:
- model — how a script is executed, the shape of its input, the rules enforced while it runs, and the mistakes that do not work here.
- functions-core — the core functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-encoding — the encoding functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-crypto — the crypto functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-text — the text functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-number — the numbers functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-structured — the structured data functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-document — the documents functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-markdown — the markdown functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-email — the email functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-blob — the files functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-mapping — the mapping functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-dataset — the datasets functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-state — the state functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-pagination — the pagination functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-control — the run control functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- functions-functions — the config functions — what each one does, its arguments, whether it pauses the run, and a line of real script.
- mistakes — the habits from general JS that do not work here — each with the exact error it produces and the shape to write instead.
- standard-library — every built-in the language itself provides —
JSON,Math,Object,String,Array,Number,Map,Set,Date,RegExpand the bare globals — one line each, with an example and its answer.