A moment.js plugin for formatting durations with comprehensive template-based formatting and localization support.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Complete internationalization support with auto-pluralization, locale-specific number formatting, and extensible locale definitions for duration unit labels and time notation templates.
Moment Duration Format extends moment.js locale objects with duration-specific localization data.
/**
* Extend moment locale with duration formatting data
* @param locale - Locale identifier (e.g., 'en', 'de', 'fr')
* @param localeData - Duration-specific locale configuration
*/
moment.updateLocale(locale: string, localeData: {
durationLabelsStandard?: DurationLabels;
durationLabelsShort?: DurationLabels;
durationTimeTemplates?: TimeTemplates;
durationLabelTypes?: LabelType[];
durationPluralKey?: PluralKeyFunction;
}): void;
interface DurationLabels {
S: string; // millisecond singular
SS: string; // millisecond plural
s: string; // second singular
ss: string; // second plural
m: string; // minute singular
mm: string; // minute plural
h: string; // hour singular
hh: string; // hour plural
d: string; // day singular
dd: string; // day plural
w: string; // week singular
ww: string; // week plural
M: string; // month singular
MM: string; // month plural
y: string; // year singular
yy: string; // year plural
}
interface TimeTemplates {
HMS: string; // hour:minute:second template
HM: string; // hour:minute template
MS: string; // minute:second template
[key: string]: string; // custom templates
}
interface LabelType {
type: string; // label type name
string: string; // replacement marker
}
type PluralKeyFunction = (
token: string,
integerValue: number,
decimalValue: number | null
) => string;Built-in English locale configuration that serves as fallback for all locales.
// Default English locale extensions
moment.updateLocale('en', {
durationLabelsStandard: {
S: 'millisecond',
SS: 'milliseconds',
s: 'second',
ss: 'seconds',
m: 'minute',
mm: 'minutes',
h: 'hour',
hh: 'hours',
d: 'day',
dd: 'days',
w: 'week',
ww: 'weeks',
M: 'month',
MM: 'months',
y: 'year',
yy: 'years'
},
durationLabelsShort: {
S: 'msec',
SS: 'msecs',
s: 'sec',
ss: 'secs',
m: 'min',
mm: 'mins',
h: 'hr',
hh: 'hrs',
d: 'dy',
dd: 'dys',
w: 'wk',
ww: 'wks',
M: 'mo',
MM: 'mos',
y: 'yr',
yy: 'yrs'
},
durationTimeTemplates: {
HMS: 'h:mm:ss',
HM: 'h:mm',
MS: 'm:ss'
},
durationLabelTypes: [
{ type: "standard", string: "__" },
{ type: "short", string: "_" }
],
durationPluralKey: function (token, integerValue, decimalValue) {
// Singular for value of 1, but not for 1.0
if (integerValue === 1 && decimalValue === null) {
return token;
}
return token + token;
}
});Automatic replacement of underscore markers with localized unit labels.
Usage Examples:
// Single underscore - short labels
moment.duration(2, "minutes").format("m _");
// "2 mins"
moment.duration(1, "hour").format("h _");
// "1 hr"
// Double underscore - standard labels
moment.duration(2, "minutes").format("m __");
// "2 minutes"
moment.duration(1, "hour").format("h __");
// "1 hour"
// Auto-pluralization
moment.duration(1, "minute").format("m __");
// "1 minute" (automatic singular)
moment.duration(2, "minutes").format("m __");
// "2 minutes" (automatic plural)Localized time notation patterns for common duration display formats.
Usage Examples:
// HMS - full time notation
moment.duration(3661, "seconds").format("_HMS_");
// "1:01:01"
// HM - hour:minute notation
moment.duration(3661, "seconds").format("_HM_");
// "1:01"
// MS - minute:second notation
moment.duration(61, "seconds").format("_MS_");
// "1:01"
// Combined with other elements
moment.duration(7322, "seconds").format("_HMS_ [elapsed]");
// "2:02:02 elapsed"Intelligent pluralization based on numeric values and decimal precision.
Usage Examples:
// Integer values
moment.duration(1, "minutes").format("m [minutes]");
// "1 minute" (singular)
moment.duration(2, "minutes").format("m [minutes]");
// "2 minutes" (plural)
moment.duration(0, "minutes").format("m [minutes]");
// "0 minutes" (plural for zero)
// Decimal values (always plural by default)
moment.duration(1, "minutes").format("m [minutes]", 2);
// "1.00 minutes" (plural due to decimal precision)
// Custom pluralization with manual labels
moment.duration(1, "minutes").format("m [minute]");
// "1 minutes" (corrected to plural automatically)
moment.duration(2, "minutes").format("m [minute]");
// "2 minutes" (corrected to plural)Extending existing locales with duration-specific labels.
Usage Examples:
// French locale extension
moment.updateLocale('fr', {
durationLabelsStandard: {
S: 'milliseconde',
SS: 'millisecondes',
s: 'seconde',
ss: 'secondes',
m: 'minute',
mm: 'minutes',
h: 'heure',
hh: 'heures',
d: 'jour',
dd: 'jours',
w: 'semaine',
ww: 'semaines',
M: 'mois',
MM: 'mois',
y: 'année',
yy: 'années'
},
durationLabelsShort: {
S: 'ms',
SS: 'ms',
s: 'sec',
ss: 'sec',
m: 'min',
mm: 'min',
h: 'h',
hh: 'h',
d: 'j',
dd: 'j',
w: 'sem',
ww: 'sem',
M: 'mois',
MM: 'mois',
y: 'an',
yy: 'ans'
}
});
// Using French locale
moment.locale('fr');
moment.duration(2, "minutes").format("m __");
// "2 minutes"
moment.duration(1, "hour").format("h _");
// "1 h"Complex locale with multiple plural forms and custom time templates.
Usage Examples:
// Example: Custom locale with three plural forms
moment.updateLocale('sample', {
durationLabelsLong: {
s: 'singular long second',
ss: 'first plural long seconds',
sss: 'many plural long seconds'
},
durationLabelsStandard: {
s: 'singular second',
ss: 'first plural seconds',
sss: 'many plural seconds'
},
durationLabelsShort: {
s: 'singular sec',
ss: 'first plural secs',
sss: 'many plural secs'
},
durationTimeTemplates: {
HMS: 'h[h]:mm[m]:ss[s]', // Custom time template
HS: 'hh[h].ssss[s]' // Custom template
},
durationLabelTypes: [
{ type: "long", string: "___" }, // Triple underscore
{ type: "standard", string: "__" }, // Double underscore
{ type: "short", string: "_" } // Single underscore
],
durationPluralKey: function (token, integerValue, decimalValue) {
// Custom pluralization logic
if (integerValue === 1 && decimalValue === null) {
return token; // "s" for exactly 1
} else if (integerValue === 2) {
return token + token; // "ss" for exactly 2
} else {
return token + token + token; // "sss" for all others
}
}
});
// Using custom locale
moment.locale('sample');
moment.duration(1, "second").format("s ___");
// "1 singular long second"
moment.duration(2, "seconds").format("s ___");
// "2 first plural long seconds"
moment.duration(5, "seconds").format("s ___");
// "5 many plural long seconds"Adding specialized time notation templates to locales.
Usage Examples:
// Add custom time templates
moment.updateLocale('en', {
durationTimeTemplates: {
HMS: 'h:mm:ss',
HM: 'h:mm',
MS: 'm:ss',
DHMS: 'd[d] h:mm:ss', // Custom: days + time
PRECISION: 'h:mm:ss.SSS' // Custom: with milliseconds
}
});
// Using custom templates
moment.duration(90061, "seconds").format("_DHMS_");
// "1d 1:01:01"
moment.duration(3661789, "milliseconds").format("_PRECISION_");
// "1:01:01.789"Override moment locale for numerical formatting only.
Usage Examples:
// Using German locale for numbers, English for labels
moment.locale('en'); // English labels
moment.duration(1234567, "seconds").format({
template: "m [minutes]",
precision: 3,
userLocale: "de-DE" // German number formatting
});
// "20.576,117 minutes"
// Compare with English number formatting
moment.duration(1234567, "seconds").format({
template: "m [minutes]",
precision: 3,
userLocale: "en-US"
});
// "20,576.117 minutes"Automatic fallback to English locale when duration extensions are missing.
Usage Examples:
// Set moment to unsupported locale
moment.locale('xyz-unknown');
// Duration formatting falls back to English
moment.duration(2, "minutes").format("m __");
// "2 minutes" (English fallback)
// But uses locale for number formatting if available
moment.duration(1234, "seconds").format("s [seconds]");
// Number formatting may vary based on system localeFunction signature for custom pluralization logic.
/**
* Determines the appropriate label key for a duration value
* @param token - Single character unit token (s, m, h, d, w, M, y, S)
* @param integerValue - Integer portion of the duration value
* @param decimalValue - Decimal portion (null if no decimal part)
* @returns Label key to use for lookup (e.g., "s", "ss", "sss")
*/
type PluralKeyFunction = (
token: string,
integerValue: number,
decimalValue: number | null
) => string;Usage Examples:
// Default English pluralization
function englishPluralKey(token, integerValue, decimalValue) {
// Singular only for exactly 1 with no decimal
if (integerValue === 1 && decimalValue === null) {
return token; // "s" -> singular label
}
return token + token; // "ss" -> plural label
}
// Custom: Slavic-style pluralization
function slavicPluralKey(token, integerValue, decimalValue) {
// Complex Slavic plural rules (simplified example)
if (integerValue === 1 && decimalValue === null) {
return token; // 1 -> singular
} else if (integerValue >= 2 && integerValue <= 4) {
return token + token; // 2-4 -> first plural
} else {
return token + token + token; // 5+ -> second plural
}
}
// Custom: Always plural
function alwaysPluralKey(token, integerValue, decimalValue) {
return token + token; // Always use plural form
}Pluralization works in conjunction with label types for complete localization.
Usage Examples:
// Set up locale with multiple label types and custom pluralization
moment.updateLocale('multi', {
durationLabelsVerbose: {
s: 'one verbose second',
ss: 'few verbose seconds',
sss: 'many verbose seconds'
},
durationLabelsStandard: {
s: 'one second',
ss: 'few seconds',
sss: 'many seconds'
},
durationLabelsShort: {
s: 'one sec',
ss: 'few secs',
sss: 'many secs'
},
durationLabelTypes: [
{ type: "verbose", string: "____" }, // 4 underscores
{ type: "standard", string: "__" }, // 2 underscores
{ type: "short", string: "_" } // 1 underscore
],
durationPluralKey: function(token, integerValue, decimalValue) {
if (integerValue === 1 && decimalValue === null) return token;
if (integerValue >= 2 && integerValue <= 4) return token + token;
return token + token + token;
}
});
// Using different label types with pluralization
moment.locale('multi');
moment.duration(1, "second").format("s ____"); // "1 one verbose second"
moment.duration(3, "seconds").format("s ____"); // "3 few verbose seconds"
moment.duration(7, "seconds").format("s ____"); // "7 many verbose seconds"