Momentesque
Updated peter.dexter@formbird.com - 2026-08-10
"Momentesque" is a ruleset include script which provides a number of functions to replace those exploited in the past from Moment.js, and is envisaged to help replace usage of Moment within ruleset scripts over time.
It also provides means to convert between legacy Date objects and newer Temporal objects.
Be aware, this replaces only the most often used functions from Moment, not its entire function catalog, so in rare cases it would be necessary to recode entirely, using Temporal date functionality, or the functions here.
If a function that was used at large scale is omitted here, please make request to peter.dexter@formbird.com to include a replacement function.
Please note, even with these provided replacement functions, it is still necessary to recode old Moment function calls.
Ruleset Include: Momentesque
Functions
- isValid
- parseWithFormat
- startOf
- add
- subtract
- format
- isSame
- isBefore
- isSameOrBefore
- isAfter
- isSameOrAfter
- temporalToDate
- diff
isValid
Checks whether a value is a valid Date, number, or ISO 8601 date/date-time string.
NB: Due to the variability of interpretation of string dates by the various browser engines, it is not possible to determine if a particular "friendly" format (eg "June 12, 2022, 3:03pm") will be "valid" in every browser instance.
Parameters
| Name | Type | Description |
|---|---|---|
| value | Date \| number \| string | The value to validate |
Returns: boolean
Accepted string formats: strictly ISO 8601 only — 2023-01-31, 2023-01-31T14:30:00, 2023-01-31T14:30:00Z, 2023-01-31T14:30:00+02:00.
momentesque.isValid("2023-06-15"); // true
momentesque.isValid("2023-06-15T14:30:00Z"); // true
momentesque.isValid("June 15, 2023"); // false — non-ISO formats no longer accepted
momentesque.isValid("01/02/2023"); // false
momentesque.isValid(new Date()); // true
momentesque.isValid(NaN); // false
parseWithFormat
Parses a date/time string using an explicit Moment-style format string.
Replaces moment's constructor function used with format string, eg
var x = moment("23 Sep 1966", "D MMM YYYY")
Parameters
| Name | Type | Description |
|---|---|---|
| str | string | The date/time string to parse |
| format | string | A format string made of the tokens below |
Returns: Date (always — including when the format includes Z, in which case the string is parsed as UTC before constructing the Date).
momentesque.parseWithFormat("14 Aug 1999, 7:04pm", "DD MMM YYYY, h:mma");
momentesque.parseWithFormat("August 14, 2023, 1:03PM", "MMMM D, YYYY, h:mmA");
momentesque.parseWithFormat("2026-08-06T01:03:05Z", "YYYY-MM-DDTHH:mm:ssZ"); // -> Date, parsed as UTC
momentesque.parseWithFormat("14 Aug 2023, 3:33:12.500pm", "DD MMM YYYY, h:mm:ss.SSSa");
momentesque.parseWithFormat("15 June 2023", "DD MMMM YYYY"); // no time tokens -> defaults to midnight
momentesque.parseWithFormat("12:00pm", "h:mma"); // no date tokens -> defaults to today's date
Throws an Error if str doesn't match format, or if a month name/abbreviation isn't recognized.
Missing date components (year/month/day) default to today's date; missing time components default to midnight (00:00:00.000).
See Format Tokens Reference for supported tokens.
startOf
Returns a new date/time value set to the start of the given period (year, month, day, hour, or minute).
Parameters
| Name | Type | Description |
|---|---|---|
| value | Date \| Temporal.* | The date/time to truncate |
| periodName | 'year' \| 'month' \| 'day' \| 'hour' \| 'minute' | Period to truncate to |
| timezoneId | string (optional) | Only used for Temporal.ZonedDateTime/Temporal.Instant input; defaults to local timezone |
Returns: Same type as value (Date in, Date out; Temporal.X in, Temporal.X out — except Temporal.Instant input returns a Temporal.Instant).
momentesque.startOf(new Date(), "day");
momentesque.startOf(Temporal.Now.zonedDateTimeISO(), "month");
momentesque.startOf(Temporal.Now.instant(), "hour", "Australia/Sydney");
momentesque.startOf(Temporal.PlainMonthDay.from("06-15"), "day");
Throws an Error if value is not a Date or recognized Temporal type.
add
Adds (or subtracts, with a negative num) a period to a legacy Date object. Month/year additions are day-clamped (e.g. adding 1 month to Jan 31 gives Feb 28, not Mar 3).
Parameters
| Name | Type | Description |
|---|---|---|
| value | Date | The date to add to (not mutated — a new Date is returned) |
| num | number | Amount to add |
| periodName | 'second' \| 'minute' \| 'hour' \| 'day' \| 'week' \| 'month' \| 'year' \| 'millisecond' | Unit of num |
Returns: Date
momentesque.add(new Date(), 5, "minute");
momentesque.add(new Date("2023-01-31"), 1, "month"); // -> Feb 28, 2023
Throws an Error if value is not a Date.
Only supports legacy Date objects — there is no Temporal equivalent in this include. Use native Temporal .add()/.subtract() methods directly for Temporal types.
subtract
Convenience wrapper around add with num negated.
momentesque.subtract(new Date(), 3, "day");
format
Formats a Date or Temporal object into a string using Moment-style format tokens.
Parameters
| Name | Type | Description |
|---|---|---|
| dt | Date \| Temporal.PlainDate \| Temporal.PlainDateTime \| Temporal.PlainTime \| Temporal.ZonedDateTime \| Temporal.Instant | Value to format |
| tokenStr | string | Format string made of tokens below |
Returns: string
momentesque.format(new Date(), "YYYY-MM-DD HH:mm:ss");
momentesque.format(Temporal.Now.zonedDateTimeISO(), "dddd, MMMM D, YYYY h:mm a");
Type handling:
- Date is converted via local timezone to a Temporal.PlainDateTime — both date and time-of-day are preserved.
- Temporal.Instant is converted to Temporal.ZonedDateTime in UTC.
- Any other value must be a Temporal.PlainDateTime, Temporal.PlainDate, Temporal.PlainTime, or Temporal.ZonedDateTime — otherwise a TypeError is thrown.
See Format Tokens Reference for supported tokens (this function supports a wider set than parseWithFormat, including dddd/ddd weekday names and A/a for AM/PM).
isSame
Checks whether two date/time values represent the exact same value (via Temporal's .equals()).
Parameters
| Name | Type |
|---|---|
| dt1, dt2 | Date \| Temporal.* |
Returns: boolean
momentesque.isSame(dateA, dateB);
Date arguments are converted to Temporal.ZonedDateTime (local timezone) before comparison.
Temporal.ZonedDateTime.equals() requires matching timezone and calendar, not just the same instant — comparing two ZonedDateTimes in different timezones representing the same moment will return false.
isBefore
Checks whether dt1 is chronologically before dt2.
Parameters
| Name | Type | Description |
|---|---|---|
| dt1 | Date \| Temporal.* | |
| dt2 | Date \| Temporal.* (optional) | Defaults to new Date() (now) if omitted |
Returns: boolean
momentesque.isBefore(pastDate, futureDate); // true
momentesque.isBefore(pastDate); // true, compared against now
Throws a TypeError if dt1 and dt2 resolve to different Temporal constructors after Date conversion.
isSameOrBefore
Convenience wrapper: isSame(dt1, dt2) || isBefore(dt1, dt2).
momentesque.isSameOrBefore(dateA, dateB);
isAfter
Checks whether dt1 is chronologically after dt2. Implemented as isBefore(dt2, dt1).
momentesque.isAfter(futureDate, pastDate); // true
isSameOrAfter
Convenience wrapper: isSame(dt1, dt2) || !isBefore(dt2, dt1).
momentesque.isSameOrAfter(dateA, dateB);
temporalToDate
Converts any Temporal object to a legacy Date, filling in sensible defaults for types missing date/timezone information.
Parameters
| Name | Type | Description |
|---|---|---|
| value | Temporal.* | Any Temporal type except Duration |
| tz | string (optional) | Timezone to anchor to; defaults to local timezone |
Returns: Date
Anchoring defaults for types missing information:
| Type | Missing | Anchored to |
|---|---|---|
| PlainTime | date | Today's date (in tz) |
| PlainYearMonth | day | 1st of the month |
| PlainMonthDay | year | Current year |
momentesque.temporalToDate(Temporal.Now.plainTimeISO());
momentesque.temporalToDate(Temporal.PlainYearMonth.from("2023-06"));
momentesque.temporalToDate(Temporal.PlainMonthDay.from("06-15"), "America/New_York");
Throws a TypeError for unrecognized types (e.g. Temporal.Duration, which has no meaningful Date equivalent).
diff
Computes the difference between two legacy Date objects in a given unit — mirrors Moment.js's .diff().
Parameters
| Name | Type | Description |
|---|---|---|
| dt1 | Date | Minuend (later/reference date) |
| dt2 | Date | Subtrahend |
| unitName | string (optional) | Any Temporal duration unit, singular or plural (e.g. "day" or "days"). Defaults to "milliseconds" |
| fractional | boolean (optional) | If falsy, result is floored to an integer (matches Moment's default). If truthy, returns a fractional value |
Returns: number
momentesque.diff(dateA, dateB, "days"); // integer days
momentesque.diff(dateA, dateB, "days", true); // fractional days
momentesque.diff(dateA, dateB); // milliseconds
Both arguments are converted internally to Temporal.Instant, and the result uses .total() with relativeTo set to dt2's date, so calendar units (months/years) resolve correctly.
Throws a TypeError if dt1 is not a Date, or if dt1/dt2 are of different constructors.
Format Tokens Reference
Used by parseWithFormat and format. Longest tokens are always matched first (e.g. YYYY before YY, MMMM before MMM/MM/M).
| Token | Meaning | parseWithFormat |
format |
|---|---|---|---|
YYYY |
4-digit year | ✅ | ✅ |
YY |
2-digit year | ✅ | ✅ |
MMMM |
Full month name | ✅ | ✅ |
MMM |
3-letter month abbreviation | ✅ | ✅ |
MM |
2-digit month | ✅ | ✅ |
M |
Non-padded month | ✅ | ✅ |
DD |
2-digit day | ✅ | ✅ |
D |
Non-padded day | ✅ | ✅ |
dddd |
Full weekday name | — | ✅ |
ddd |
3-letter weekday abbreviation | — | ✅ |
HH |
2-digit hour (24h) | ✅ | ✅ |
H |
Non-padded hour (24h) | ✅ | ✅ |
hh |
2-digit hour (12h) | ✅ | ✅ |
h |
Non-padded hour (12h) | ✅ | ✅ |
mm |
2-digit minute | ✅ | ✅ |
m |
Non-padded minute | ✅ | ✅ |
ss |
2-digit second | ✅ | ✅ |
s |
Non-padded second | ✅ | ✅ |
SSS |
3-digit millisecond | ✅ | ✅ |
a |
am/pm (lowercase) | ✅ | ✅ |
A |
AM/PM (uppercase) | ✅ | ✅ |
Z |
UTC marker (parsed as UTC before constructing the returned Date) |
✅ | — |
Any character in the format string not matching a token is treated as a literal (spaces, commas, colons, etc.) and escaped automatically for regex safety in parseWithFormat.