Skip to content

Writing Style

Karthik P edited this page Oct 26, 2026 · 2 revisions

This page sets the rules for every word on the website and in this wiki: voice, terms, how to write times and code samples, error messages, headings, links and callouts. Follow it when writing or reviewing a docs page, a landing section or a message the demo shows.

The words for what the library computes come from DESIGN.md. When this page and DESIGN.md disagree about a term, DESIGN.md wins and this page is fixed.

Voice

Plain, exact, calm.

  • Plain. Short sentences, everyday words, one idea per sentence. "Use", not "leverage"; "about", not "approximately".
  • Exact. Give the number, the date, the type name. "Due at 09:30 on Wednesday 30 December 2026", not "due a few days later". "Raises ValueError", not "fails".
  • Calm. No exclamation marks, no "simply" or "just", no "blazing", "powerful", "robust", "seamless" or "effortless". Don't predict how the reader feels.
  • Verifiable. Every claim points at something the reader can run or read: a DESIGN.md example ID, a test file, the demo or benchmarks/RESULTS.md. A claim without a link is rewritten until it has one, or deleted.
Write Don't write
add returns the earliest instant after t with exactly d of working time between them. workclock intelligently figures out when things are due.
A 22:00–06:00 shift counts 8 hours between Monday 22:00 and Tuesday 06:00 (DESIGN.md O1). Handles tricky overnight shifts with ease.
One between call takes a median of 1.2 µs from Rust on the benchmark runner (RESULTS.md). Blazing fast.
Not in 0.1.0: converting a duration into business days. Business-day support coming soon!

Say what workclock does not do as plainly as what it does. The limits in DESIGN.md's Scope section (no duration-to-business-days, no per-date overrides of working hours) go on the pages where a reader would look for them.

Spelling and case

  • British spelling, as in the rest of the wiki: colour, behaviour, licence (noun). Identifiers, quotations and product names keep theirs (color in CSS, "MIT License").
  • workclock is always lowercase, even at the start of a sentence (Brand).
  • Sentence case for every heading, button, tab, menu item, table header and page title: "Time zones and DST". Proper nouns and identifiers keep their case.
  • No all-caps labels. Abbreviations keep their usual form: SLA, DST, IANA, UTC, API, CI.

Terminology

These match DESIGN.md and the README.

Term Meaning Notes
working time The time a schedule counts: available blocks merged, minus time off Use it for results: "8 hours of working time".
working hours The wall-clock times in a rule, such as 09:00–17:00 Not "business hours" or "office hours" in docs prose.
business-time arithmetic What the library does Only in the one-line description and when talking about businesstimedelta.
schedule A set of rules with a default time zone; Schedule in every language Not "calendar", "timetable" or "config".
rule One input to a schedule, either available or time off WorkDay is available; Break and Holidays are time off.
WorkDay Working hours on given weekdays Never "Workday" or "work-day rule". compat: WorkDayRule.
Break A recurring time-off rule, same shape as WorkDay compat: LunchTimeRule.
Holidays A set of local dates removed from 00:00 to the next 00:00 One date is "a holiday". compat: HolidayRule.
time off Breaks and holidays together Not "downtime" or "exclusions".
shift One run of a WorkDay rule on one date "Overnight shift" when end is at or before start; "24-hour shift" when equal.
period A maximal stretch of working time, [start, end) What next_period and previous_period return.
instant An absolute point in time In a language's sample, its type: jiff::Zoned or jiff::Timestamp, an aware datetime, a Date. Not "timestamp" in prose.
duration Elapsed real time, possibly negative Not "interval".
time zone Two words; "zone" for short; always an IANA name Identifiers keep their form: time_zone, timeZone.
DST Daylight saving time Spell out once per page. Never "daylight savings".
gap, overlap Spring-forward and fall-back local times As in DESIGN.md.
search bound 366 days, plus seven per holiday date, after which a search stops Not "timeout" or "limit".
typed API workclock.Schedule and its rules As opposed to the compatibility layer.
compatibility layer, compat workclock.compat Code font when it is the module.
businesstimedelta The project workclock replaces Lowercase, no code font unless an import. Add "1.0.1" when the version matters.
no-working-time, out-of-range, unknown-zone error The three error kinds In a language's text, the class: NoWorkingTimeError, OutOfRangeError, UnknownZoneError, workclock::Error::NoWorkingTime.
batch methods between_many, add_many, sub_many; betweenMany, addMany, subMany Not "vectorised API".

Operation names follow the language: next_period in Rust and Python, nextPeriod in JavaScript; Rust and Python names in language-neutral text, as DESIGN.md does.

Avoid, because workclock does not do them: "business days" as a unit, "calendar", "working-hours override", "holiday calendar for country X" (workclock takes dates; python-holidays objects are accepted, but no holiday data ships).

Times, dates, durations and numbers

Readers compare these to their own output, so write them the same way every time. Set them all with tabular figures (Typography).

What Prose Tables, specs, code comments
Time of day 24-hour HH:MM with leading zero: 09:30, 17:00 Same
Time range En dash, no spaces: 09:00–17:00 Same; hours only in DESIGN.md-style example tables: 9–17, 22–06
Date Wednesday 30 December 2026; no ordinal, no comma; drop weekday or year when obvious ISO 8601: 2026-12-30
Date and time Time first: 09:30 on Wednesday 30 December 2026 2026-12-30 09:30
Instant Plus the zone: 09:30 on 30 December 2026, London time RFC 3339 with an offset, in code font: 2026-12-30T09:30:00Z, 2026-01-26T09:30:00+05:30
Weekday Monday; "Monday to Friday" Mon; Mon–Fri
Duration 8 hours, 30 minutes, 2 hours 30 minutes; "an 8-hour SLA" as an adjective DESIGN.md style: 8h, 30m, -2h
Measured time Number, no-break space, unit: 3.89 µs, 2.11 s, 9.86 min Same, one unit per column
Speed-up Number and ×: 43×, 600× Same
Large numbers Comma separator: 1,000,000 Underscores in code: 3_600_000
Demo due label Due Wed 30 Dec, 09:30
Demo result sentence Due 09:30 on Wednesday 30 December 2026 (Europe/London)

Rules:

  • No wall-clock time without its zone, unless the page has stated the zone for the whole example: "opened at 16:30 London time", "16:30 in Europe/London".
  • Zones by IANA name: Europe/London, America/New_York, Asia/Kolkata. A city ("London time") is fine once the IANA name has appeared. EST, BST or IST only next to an offset or IANA name; they are ambiguous (IST is India, Ireland and Israel).
  • UTC, not GMT, for the zero offset. GMT is London's winter time.
  • No 12-hour clock, no AM/PM, no numeric dates like 12/30/2026 or 30/12/2026.
  • When a result depends on DST, name the transition: "Clocks go back in America/New_York on Sunday 1 November 2026."

Code samples

Every sample on the site obeys these rules. They make the samples trustworthy and let an agent copy one into a project.

  1. It runs as written. All imports, no ..., no undefined names. Rust samples have fn main() -> Result<(), Box<dyn std::error::Error>> and return Ok(()), as the README does. A fragment that cannot run alone is titled "Fragment" and still has its imports.

  2. One scenario. The London support desk from the README, unless the page is about something it cannot show (an overnight shift, a DST change):

    A support desk in London works 09:00–17:00 on weekdays with a lunch hour, and is closed on 25 and 28 December 2026. A ticket opened at 16:30 on Christmas Eve with an 8-hour SLA is due at 09:30 on 30 December.

    Values: zone Europe/London; WorkDay 09:00–17:00 Monday to Friday; Break 12:00–13:00; Holidays 2026-12-25 and 2026-12-28; opened 2026-12-24 16:30; SLA 8 hours; due 2026-12-30 09:30; working time used by 2026-12-29 11:00 is 2 hours 30 minutes. Variable names in every language: support, opened, due, now.

  3. Same answer in every language. Rust, Python and JavaScript tabs, in that order, reaching the same instant. Copy the README's code; don't paraphrase it.

  4. Expected output in a comment, in the form each test suite checks:

    Language Form Example
    Rust assert_eq! on the result assert_eq!(due.to_string(), "2026-12-30T09:30:00Z");
    Python A comment with the value and zone support.add(opened, hours=8) # 2026-12-30 09:30, London time
    JavaScript // Date <ISO string> or // <number> ms support.add("2026-12-24T16:30:00Z", 8 * 3_600_000); // Date 2026-12-30T09:30:00.000Z

    The JavaScript form is what js/test/readme.test.ts checks.

  5. Aware datetimes only. Python passes tzinfo (zoneinfo.ZoneInfo); the typed API raises ValueError for a naive datetime. JavaScript instants are Dates or ISO 8601 strings with an offset. Rust uses jiff::Zoned or jiff::Timestamp. The only naive datetimes are in workclock.compat samples, which say compat treats them as UTC.

  6. Durations in each language's unit. Rust SignedDuration::from_hours(8); Python hours=8 or timedelta(hours=8); JavaScript milliseconds written as arithmetic, 8 * 3_600_000, not 28800000.

  7. Real names. support, not foo, s or my_schedule. No placeholders like YOUR_ZONE.

  8. Short. One idea. Over about 25 lines, link the full program in crates/workclock/examples, examples/python or js/examples. Lines of 77 characters or fewer (Typography).

  9. Install commands are the README's: cargo add workclock jiff, pip install workclock, uv add workclock, npm i workclock. Before 0.1.0, every install block carries the status line (Brand).

  10. Shell blocks have no $ prompt.

  11. A language tag on every fence: rust, python, js, ts, sh, toml, json. Tab labels are "Rust", "Python", "JavaScript".

Error messages

Messages the site shows (the demo, build checks):

  • What happened, then what to do, in one or two sentences: "No working time: pick at least one working day." Not "Error!" or "Something went wrong".
  • Name the input in the reader's words: "the SLA", "the holidays", "Saturday".
  • No blame, no apology, no jokes.
  • Next to the input it refers to, in danger text with an icon, announced to screen readers (Accessibility).

Describing the library's errors:

  • Name the class and when it is raised, per language, from DESIGN.md's Errors and termination: "Schedule(...) raises NoWorkingTimeError if the rules leave no working time over a 14-day reference window."
  • Give a Python error's base classes when it matters for except: NoWorkingTimeError is a WorkclockError and a ValueError.
  • Quote real messages only by copying them from the library's output.
  • Never "throws an exception" generically; say what is raised or returned.

Headings

  • One H1 per page, from the front matter title; don't repeat it in the body.
  • H2 for sections, H3 for subsections. Don't skip levels or go below H3; split the page instead.
  • Task pages use a verb ("Count working time between two instants"); reference pages use the thing's name ("Schedule.add").
  • Short (under about 60 characters) and unique on the page: they become anchors and "On this page" entries.
  • No questions except on the FAQ, no closing punctuation, no numbering in the text.
  • Don't reword a published heading without checking for links to its anchor.

Link text

  • Says where it goes: "see Time zones and DST", not "click here".
  • Link the most specific place: a DESIGN.md anchor, a test file, an issue.
  • File links show the path: "benchmarks/RESULTS.md".
  • Wiki pages use [[Page Name]]; site pages use full paths from the docs root.
  • External links go to primary sources: jiff docs, the IANA database, RFC 5545, WCAG, Fumadocs and Next.js docs.
  • Don't link the same target twice in one section.

Callouts

Only when a reader would otherwise make a mistake; at most one per screen, never two in a row. Visuals on Components.

Kind Colour Use for Example
Note info A needed fact that does not fit the flow "The npm package always uses its bundled IANA time zone database; on Linux and macOS the Rust crate uses the system's."
Warning accent / accent-text Something that silently gives a wrong answer if missed; the pre-release status line "NumPy datetime64 values carry no zone, so between_many, add_many and sub_many read them as UTC."
Danger danger Data loss or a broken build Not used on any page yet.

No "Tip:", "Pro tip" or "Did you know".

Writing pages that agents can use

Many readers reach a page through a coding agent that fetches one page, or its Markdown version, and writes code from it. These rules serve that reader and the one who lands from search. Agent Experience covers what the site provides.

  • Self-contained. The first paragraph says what the page covers and for which language or languages. It never relies on the page before it.
  • No positional references: no "see above", "as shown below", "the previous example". Name the section and link it.
  • Explicit imports in every sample, even the third on the page.
  • Full type names on first mention in each section: workclock.Schedule, workclock.NoWorkingTimeError, jiff::SignedDuration, workclock::Weekdays::MON_TO_FRI.
  • State the language before a single-language sample: "In Python:". The Markdown version keeps tab labels, because tabs disappear in plain text.
  • Units and zones on every value. An agent cannot guess that a JavaScript duration is in milliseconds.
  • One fact, one form. Requirements (Rust 1.85, CPython 3.9, Node.js 22), install commands and error classes are written the same way on every page, so two pages never seem to contradict.
  • Plain Markdown survives. Anything only in a diagram, hover or interactive component also appears as text.
  • Version-stamp claims that change: "In 0.1.0, …". Benchmark figures give the date and machine.

Open items

  • Proposed: run the website's code samples with the same tests that run the README's, so a sample that stops matching its comment fails CI (Agent Experience, build checks).

Clone this wiki locally