@adaskothebeast/http-params-processor-value-from-moment
v12.0.0
Published
Moment date and duration input strategies for HttpParamsProcessor value conversion.
Maintainers
Readme
⏱️ @adaskothebeast/http-params-processor-value-from-moment
Moment.js input strategies for HttpParamsProcessor: normalize Moment instants and moment.Duration objects before they are serialized.
Peer dependencies: core and moment (^2.30.1). ESM + CJS. sideEffects: false.
📦 Install
npm i @adaskothebeast/http-params-processor-value-from-moment @adaskothebeast/http-params-processor-core momentmoment-timezone is only needed if your code builds moments in named IANA zones (moment.tz(...)); the strategies themselves never touch zone data.
🎯 What it does
These are value-from strategies: the first half of the conversion pipeline. Each one normalizes a Moment type into a neutral shape and must be paired with a value-to strategy (-value-to-iso, -value-to-nodatime, -value-to-unix-timestamp, -value-to-ms-timestamp, -value-to-date-fns) through createValueConverter.
| Class | Accepts | Produces |
| --------------------------------- | --------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| MomentDateValueFromStrategy | Moment (detected by moment.isMoment) | Date (value.toDate()) |
| MomentDurationValueFromStrategy | moment.Duration (detected by moment.isDuration) | DurationComponents (years, months, days, hours, minutes, seconds, milliseconds) |
Detection is exact and mutually exclusive: a Moment is never claimed by the duration strategy and vice versa, so both converters can be registered side by side.
⚡ Usage
import { DefaultDateValueFromStrategy, ParamsProcessor, createValueConverter } from '@adaskothebeast/http-params-processor-core';
import { MomentDateValueFromStrategy, MomentDurationValueFromStrategy } from '@adaskothebeast/http-params-processor-value-from-moment';
import { IsoDateValueToStrategy, IsoDurationValueToStrategy } from '@adaskothebeast/http-params-processor-value-to-iso';
import moment from 'moment';
const processor = new ParamsProcessor({
valueConverters: [
createValueConverter(new MomentDateValueFromStrategy(), new IsoDateValueToStrategy()),
createValueConverter(new MomentDurationValueFromStrategy(), new IsoDurationValueToStrategy()),
// keep native Dates working too
createValueConverter(new DefaultDateValueFromStrategy(), new IsoDateValueToStrategy()),
],
});
processor.process('p', {
from: moment.utc('2024-01-15T10:30:00.000Z'),
window: moment.duration({ hours: 1, minutes: 30, seconds: 45 }),
});
// [['p.from', '2024-01-15T10:30:00.000Z'], ['p.window', 'PT1H30M45S']]🎛️ Options and configuration
Neither strategy takes constructor options - both are stateless and safe to share between processors.
Zones and UTC mode collapse into an instant. toDate() returns a native Date, so moment.utc(...), moment.parseZone(...) and moment.tz(..., 'Asia/Tokyo') all serialize to the same moment in time; the offset itself is not carried. The paired writer decides the rendering (-value-to-iso always emits UTC with Z).
Moment normalizes durations for you. Unlike Luxon and Day.js, moment.duration carries units on construction, so what you get out can differ from what you put in - see the table below.
Output format is decided by the paired value-to strategy:
import { MsTimestampValueToStrategy } from '@adaskothebeast/http-params-processor-value-to-ms-timestamp';
createValueConverter(new MomentDateValueFromStrategy(), new MsTimestampValueToStrategy());📤 Output examples
Paired with -value-to-iso:
| Value passed to process | Normalized shape | Serialized |
| ---------------------------------------------------- | ---------------------------------------- | -------------------------- |
| moment.utc('2024-01-15T10:30:00.000Z') | Date (instant) | 2024-01-15T10:30:00.000Z |
| moment.duration({ hours: 1, minutes: 30 }) | { hours: 1, minutes: 30 } | PT1H30M |
| moment.duration({ minutes: 90 }) | { hours: 1, minutes: 30 } | PT1H30M |
| moment.duration({ months: 18 }) | { years: 1, months: 6 } | P1Y6M |
| moment.duration({ days: 45 }) | { months: 1, days: 14 } | P1M14D |
| moment.duration({ weeks: 2 }) | { days: 14 } | P14D |
| moment.duration({ seconds: 1, milliseconds: 500 }) | { seconds: 1, milliseconds: 500 } | PT1.5S |
| moment.duration('PT1H30M45S') | { hours: 1, minutes: 30, seconds: 45 } | PT1H30M45S |
p.from = 2024-01-15T10:30:00.000Z
p.window = PT1H30M45S⚠️ Edge cases
- Moment carries units, so values change shape.
{ minutes: 90 }comes back as 1 hour 30 minutes,{ months: 18 }as 1 year 6 months, and large day counts roll into months ({ days: 45 }becomes 1 month 14 days, using Moment's approximate 30.4-day month). SendasDays()/asSeconds()numbers instead if the backend needs the exact unit you authored. - Weeks are folded into days. Moment reports
moment.duration({ weeks: 2 }).days()as14, and the strategy does not map aweeksfield at all, so you getP14D, neverP2W. - Zero components are converted to
undefined, so{ hours: 1 }never emits0days or minutes, andmoment.duration(0)normalizes to an empty object (PT0Swith the ISO writer). - Invalid moments still pass
canHandle.moment('nope')andmoment.invalid()areMomentobjects, so they are claimed and normalized toInvalid Date;IsoDateValueToStrategythen throwsRangeError: Invalid time value(timestamp writers emitNaN). Guard with.isValid()before building your params object. - Fractional seconds are carried into the millisecond field (
{ seconds: 1.5 }becomes{ seconds: 1, milliseconds: 500 }), which the ISO writer renders asPT1.5S. - Negative durations keep their sign per component, which produces non-standard output such as
PT-1H- normalize with.abs()and send the sign separately if that matters. moment.Durationvalues are not instants; never pairMomentDurationValueFromStrategywith a date writer such asIsoDateValueToStrategy- the converter always runs the paired writer, it does not re-check the shape.- Moment is in maintenance mode upstream; for new code prefer
-value-from-luxonor-value-from-dayjs. Both can be registered next to this package during a gradual migration.
🔗 Related packages
- Outputs:
-value-to-iso,-value-to-nodatime,-value-to-unix-timestamp,-value-to-ms-timestamp,-value-to-date-fns - Other inputs:
-value-from-luxon,-value-from-dayjs,-value-from-js-joda - Engine:
-core
Full matrix and adapter recipes: main README.
📄 License
MIT © Adam Pluciński
