a9script

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 from new 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.YYYY or YYYY-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 dates formatDate takes.
  • 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, second or millisecond — plurals work too.
  • timeZone (string, optional) — Whose calendar to walk, such as Europe/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, second or millisecond — plurals work too.
  • timeZone (string, optional) — Whose calendar to walk, such as Europe/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, second or millisecond — plurals work too.
  • timeZone (string, optional) — Whose calendar to walk, such as Europe/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 of year, month, week, day, hour, minute, second or millisecond — 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 of year, month, week, day, hour, minute, second or millisecond — 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 of year, month, week, day, hour, minute, second or millisecond — 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, second or millisecond — plurals work too.
  • timeZone (string, optional) — A timezone name such as Europe/Vienna, or UTC. 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, second or millisecond — plurals work too.
  • timeZone (string, optional) — A timezone name such as Europe/Vienna, or UTC. 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 tokens YYYY, MM, DD, HH, mm, ss and SSS; everything else in the pattern must appear in the text as it stands. What the pattern does not name starts the period, so YYYY-MM reads 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 and 26 cannot say which century it means.
  • timeZone (string, optional) — Which timezone the text is written in — 2026-07-14 12:30 means 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. YYYY and YY for the year, MM for the month and MMM/MMMM for its name, DD for the day and DDD/DDDD for the weekday’s name, HH, mm, ss and SSS for the time. Every other character is written as it stands.
  • timeZone (string, optional) — A timezone name such as Europe/Vienna, or UTC. 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 as de-DE. Defaults to en-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, or weekday (1 for Monday through 7 for Sunday).
  • timeZone (string, optional) — A timezone name such as Europe/Vienna, or UTC. 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, second or millisecond. The weekday cannot be set — move the date with dateAdd instead.
  • 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 as dateAdd does.
  • timeZone (string, optional) — A timezone name such as Europe/Vienna, or UTC. 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 as Europe/Vienna, or UTC. 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 as Europe/Vienna, or UTC. 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 as Europe/Vienna, or UTC. 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, RegExp and the bare globals — one line each, with an example and its answer.
Rendered from docs/guide/authoring-pack-functions-datetime.md in the product's own repository, at build time. Found a problem on this page? Write to the address in the footer.