Compare any two workflow dates and write the gap as natural-language English — “in 2 years, 3 months”, “5 days ago”, “today”. Every part of the wording is configured per-instance, so the same action drives task titles, notification emails, badge labels, and SLA branches without a code change.
43/43 unit tests passing1 Visual Workflow action4 outlets — past · future · same-day · errorCalendar math (months ≠ 30 days)Built on Alterspective Foundry
This is the same engine that runs in the designer’s Live Preview and on Sharedo’s server at workflow runtime. Pick test dates, drive every setting, and see exactly what the action will write — including which outlet would fire. No deployment, no save-run-inspect loop.
⌚ Live engine
📑 Try a preset
⚙ Settings
🔬 Style matrix
The same dates rendered at the same settings, swapping only the style. Useful for picking the right style at the design stage.
What this action solves
A named, versioned, tested home for date-formatting logic
Sharedo workflows often need to render a duration as plain English — settlement countdowns in task titles, limitation deadlines in notification emails, branches that route on whether a date is in the past, future, or today. Out of the box, the only path is the Advanced > JavaScript action: inline string concatenation, copy-pasted across workflows, untested, drift-prone. Per WFL-WA-09, that pattern must be promoted to a custom action when reused. This is that action.
Capability
Inline JavaScript
Date Difference (Plain English)
Format “in 2 years, 3 months”
Hand-rolled string concat per workflow
One action; per-instance config
Calendar math (Feb 29, month-borrow, leap-year)
Easy to get wrong with (toMs - fromMs) / 86400000 / 30
Calendar arithmetic, 43 unit tests cover the edge cases
Branch on past / future / same-day
Author writes their own if (sign < 0) tree
Three dedicated outlets — wire each to a different step
Configurable units, conjunctions, labels
Code change & redeploy
Designer fields — no code touch
Error contract on parse failure
Silent error; workflow continues with NaN in a string
required-error outlet + /String error variable per WFL-WA-11
Preview before saving
Save, run, inspect, repeat
Live preview panel; tester right above for free
Discoverability
Buried in step config; invisible to other authors
Listed in toolbox under Alterspective utility
The action
One action, four outlets, twenty-four designer fields
Drag from the toolbox under Alterspective utility. Configure once, reuse everywhere.
⌚
Date Difference (Plain English)
alt-fo-shared-wf-date-difference
Reads two date variables, computes the duration between them with calendar arithmetic, and writes a configurable plain-English string — plus optional numeric components, direction, and sign — back to workflow variables. Pure local computation: no HTTP, no side effects beyond the variable writes, idempotent and safe to retry.
Inputs: two Date Time variables (or ISO-string variables); optional date-format hint (auto / ISO 8601 / four regional patterns / custom strptime tokens)
Primary output: a /String formatted result — the variable referenced by everything downstream
Optional outputs: years, months, days, hours, minutes, totalDays, direction, sign — bind any subset
Format style: verbose (“2 years, 3 months and 5 days”), short (“2y 3mo 5d”), or iso (“P2Y3M5D”)
Unit cap: largest + smallest units, plus a max-component cap
Direction wording: free-text templates with {value} placeholder
Custom labels: optional JSON map for non-English deployments
Error contract: required-error outlet + designated /String error variable populated on parse failure, cleared on success per WFL-WA-11
pastfuturesame-dayrequired-error
Output gallery
The same engine, eight different configurations
A spread of real-world configurations and the strings they produce. Pre-rendered at build time so you see exactly what the runtime writes — no JavaScript required to display these.
Settlement
"in 2 years and 3 months"
verbose · 2 units · days minimum
2026-05-01 → 2028-08-06
Limitation overdue
"5 days overdue"
verbose · 1 unit · custom past template
2026-05-01 → 2026-04-26
SLA short countdown
"in 4h 30m"
short · 2 units · minutes minimum
2026-05-01T08:00:00Z → 2026-05-01T12:30:00Z
ISO duration
"P2Y3M5D"
iso · max 5 units · machine format
2026-05-01 → 2028-08-06
Same-day notification
"due today"
verbose · custom same-day text
2026-05-01 → 2026-05-01
German (custom labels)
"in 2 Jahre and 3 Monate"
verbose · custom labels JSON · custom templates
2026-05-01 → 2028-08-06
Conversational
"in 2 years, 3 months, and 5 days"
verbose · oxford comma · 3 units
2026-05-01 → 2028-08-06
Compact months
"in 27 months and 5 days"
verbose · months largest · roll years into months
2026-05-01 → 2028-08-06
In the designer + on the canvas
Branded, documented, configurable
Click the action node to open the configuration panel. Three things distinguish it from OOB Sharedo at a glance: the Alterspective-branded header bar, the always-visible Live Preview pane, and the one-click Help button.
Action node on the canvas — the four outlets (Past, Future, Same day, Error) align with the runtime contract documented in WFL-WA-11. The clock icon and Alterspective category make the action easy to find in mixed workflows.Branded header + live preview + inputs — the gradient header carries the Alterspective wordmark, action title, and Help toggle. The Live Preview pane re-runs on every keystroke. The variable pickers below filter for Date Time by default.Format section — eight fields control how the duration is rendered. Style swaps between verbose, short, and ISO 8601. Largest / smallest unit + max units control which components appear (and how many). Hide-zero-units strips noise; pluralise and conjunction tune wording. Custom labels accepts a JSON map for non-English deployments.
Live preview as a feature
Two test-date pickers default to today + 90 days. The result, outlet badge, and numeric breakdown update reactively as you change any setting.
Same engine as runtime
The preview runs the identical parse, calendar-breakdown, and format pipeline as the server-side template — not an approximation.
Errors surface in the panel
Type a bad date or invalid format hint, and the preview pane shows the same [validation] error message the runtime would emit.
One-click Help
The Help button toggles a panel showing three worked examples, the full outlet contract, and tips for common gotchas.
Example scenarios
Three real uses, three different configurations
The same action drives all three of these — only the per-instance configuration differs. Try each preset in the tester at the top of the page to see the result render live.
Scenario 1: Settlement countdown in a task title. A property settlement task should display “in 2 years, 3 months” until the matter completes.
1
Action runs on the matter’s daily refresh workflow
Reads two Date Time variables, computes the gap with calendar math, writes the natural-language result.
date-difference · start=today, end=settlementDate → "in 2 years, 3 months"
2
Update task title with the formatted string
A downstream Update Work Item step uses the natural-text variable as the new task title.
3
Past-direction branch fires after settlement date
If the settlement date is missed, the action’s past outlet fires and the workflow routes to a settlement-overdue escalation. Same action; the outlet you wired tells the workflow what to do.
Scenario 2: Limitation date overdue badge in an email. A litigation matter notification needs to show “5 days overdue” when the limitation date has passed, or “in 14 days” when it’s approaching.
1
Action runs in the daily reminder workflow
Three outlets, three branches: future → “Limitation in 14 days” reminder; past → “5 days overdue” escalation alert; same-day → “Limitation today — review now”.
Scenario 3: SLA tier classification by total days. An incoming enquiry should be tagged with an SLA tier based on how many days have passed since it was received.
1
Wire only the numeric output you need
Empty natural-text variable is fine when only the numeric output matters. Downstream ifBlock branches on totalDays < 1 → Tier 1, 1..3 → Tier 2, >3 → Tier 3.
Why is "1 month" sometimes shown as "30 days" or "31 days"?
The action does calendar math, not 30-day-month math. One calendar month from January 31 is February 28 (or 29 in a leap year), not "30 days later". The breakdown reflects this: from 2026-01-31 to 2026-02-28 is 28 days, not 1 month.
If you want simple 30-day chunks for a budget calculation, set Largest unit = days and read totalDays directly — the formatter will report "X days" without trying to roll up.
Can I use this on date variables that are stored as strings?
Yes. The variable picker filters for Date Time by default (the canonical type), but at runtime the parser also accepts ISO 8601 strings, regional date patterns (dd/MM/yyyy, MM/dd/yyyy, etc.), and custom strptime tokens. Wire in a String variable, set the format hint, and it works.
What happens when one of the date variables is empty or unparseable?
The action takes the required-error outlet and writes a classified message to the designated error variable: [validation] Could not parse start date "..." (HTTP 0). On the next successful run, the error variable is cleared. This contract is enforced by WFL-WA-11 and verified by tests.
Does the preview in the designer match what runs in production?
Yes. The designer's Live Preview engine is a behavioural mirror of the server-side template — same parse logic, same calendar arithmetic, same format pipeline. Both sides are exercised by the same 43 unit-test assertions. If the preview shows "in 2 years, 3 months", that's exactly what the workflow variable will contain at runtime.
Can I localise the output for non-English deployments?
Yes — pass a JSON object in Custom labels overriding any of: year/years, month/months, day/days, hour/hours, minute/minutes. Use the German preset in the tester above as a worked example. For direction wording, use the Future template / Past template / Same-day text fields.
Is this action idempotent?
Yes. Pure local computation, no side effects beyond writing to the configured workflow variables, no API calls, no shared state. Run it twice on the same inputs and the outputs are identical. WFL-WA-01 compliance verified.
How do I deploy this action to my Sharedo tenant?
The package ships a scripts/deploy.mjs that handles OAuth (Impersonate Fixed flow), folder creation, file create/update, config-cache flush, browser-cache-key reset, and the AppDomain reload required for fresh widget manifests. Set BN_VNEXT_CLIENT_SECRET (or your tenant's equivalent) in the environment and run node scripts/deploy.mjs. See the package README.md for full details.
Standards compliance
Built to the Sharedo workflow-action standards
Every applicable rule from the Alterspective Sharedo standards catalogue is honoured — cited here so reviewers and auditors can trace each capability back to its rule ID.
WFL-WA-01
Idempotent — pure compute, no side effects beyond variable writes; safe to retry
Inputs validated before execution — both date variables, format hint, max-units range, custom-labels JSON
WFL-WA-06
No direct database modifications — pure local computation, no API calls
WFL-WA-09
Custom action over inline JS for reused logic — this is the canonical form
WFL-WA-10
Dual-audience description — manifest carries both BUSINESS and TECHNICAL summaries
WFL-WA-11
Failure outlet contract — designated /String error variable populated on failure ([class] reason (HTTP 0)) and cleared on success
WFL-TS-01
Test plan — 43 vitest tests cover happy path, calendar edge cases, all 7 date-format hints, all 3 styles, conjunctions, custom labels, recovery contract
WFL-TS-07
Failure-route verified — tests confirm the required-error outlet fires on parse failure, error variable is populated, and recovery clears it on next success
NAM-PX-04
alt- prefix — Alterspective IP
NAM-WF-01
System name follows [prefix]-[area]-[context]-wf-[purpose] — alt-fo-shared-wf-date-difference
IDE-FN-01
Built on Alterspective Foundry SDK — mandatory framework for all custom widgets, aspects, and workflow actions
Engineering notes
How it’s wired
Pure local computation — no HTTP calls, no Sharedo API dependencies. The template runs in Sharedo’s Jint engine on the server but only uses standard JS Date arithmetic.
Calendar math, not millisecond math — year/month/day breakdown uses calendar arithmetic with proper month-borrow and leap-year handling. Sub-day components come from the millisecond delta.
Three implementations of the same engine stay in sync: the server-side template, the designer’s Live Preview, and the tester on this page. Drift is caught by the 43 vitest tests on the canonical implementation. A future Foundry refactor will extract a shared TS module.
Designer header is self-contained — gradient bar with the Alterspective brand mark, scoped CSS via .alt-wf-date-difference-designer so nothing leaks into Sharedo’s modeller. No external CSS file to deploy.
Deploy via the Foundry CLI pattern — foundry deploy handles auth, folder creation, file create/update, config-cache flush, browser-cache-key reset, and the AppDomain reload required for fresh widget manifests.